committed by
GitHub
9 changed files with 523 additions and 0 deletions
@ -0,0 +1,43 @@ |
|||||
|
from typing import List |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-images/") |
||||
|
async def upload_images( |
||||
|
files: List[UploadFile] = File(description="Multiple images"), |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
results = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
await file.seek(0) |
||||
|
|
||||
|
results.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"content_type": file.content_type, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(results), "files": results} |
||||
@ -0,0 +1,43 @@ |
|||||
|
from typing import Annotated |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-images/") |
||||
|
async def upload_images( |
||||
|
files: Annotated[list[UploadFile], File(description="Multiple images")], |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
results = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
await file.seek(0) |
||||
|
|
||||
|
results.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"content_type": file.content_type, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(results), "files": results} |
||||
@ -0,0 +1,43 @@ |
|||||
|
from typing import Annotated |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-images/") |
||||
|
async def upload_images( |
||||
|
files: Annotated[list[UploadFile], File(description="Multiple images")], |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
results = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
await file.seek(0) |
||||
|
|
||||
|
results.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"content_type": file.content_type, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(results), "files": results} |
||||
@ -0,0 +1,55 @@ |
|||||
|
import shutil |
||||
|
from pathlib import Path |
||||
|
from typing import List |
||||
|
from uuid import uuid4 |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
UPLOAD_DIR = Path("uploaded_files") |
||||
|
UPLOAD_DIR.mkdir(exist_ok=True) |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-product-images/") |
||||
|
async def upload_product_images( |
||||
|
files: List[UploadFile] = File(description="Product images"), |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
saved = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
file_ext = Path(file.filename).suffix |
||||
|
unique_name = f"{uuid4()}{file_ext}" |
||||
|
file_path = UPLOAD_DIR / unique_name |
||||
|
|
||||
|
await file.seek(0) |
||||
|
with file_path.open("wb") as buffer: |
||||
|
shutil.copyfileobj(file.file, buffer) |
||||
|
|
||||
|
saved.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"saved_as": unique_name, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(saved), "files": saved} |
||||
@ -0,0 +1,55 @@ |
|||||
|
import shutil |
||||
|
from pathlib import Path |
||||
|
from typing import Annotated |
||||
|
from uuid import uuid4 |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
UPLOAD_DIR = Path("uploaded_files") |
||||
|
UPLOAD_DIR.mkdir(exist_ok=True) |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-product-images/") |
||||
|
async def upload_product_images( |
||||
|
files: Annotated[list[UploadFile], File(description="Product images")], |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
saved = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
file_ext = Path(file.filename).suffix |
||||
|
unique_name = f"{uuid4()}{file_ext}" |
||||
|
file_path = UPLOAD_DIR / unique_name |
||||
|
|
||||
|
await file.seek(0) |
||||
|
with file_path.open("wb") as buffer: |
||||
|
shutil.copyfileobj(file.file, buffer) |
||||
|
|
||||
|
saved.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"saved_as": unique_name, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(saved), "files": saved} |
||||
@ -0,0 +1,55 @@ |
|||||
|
import shutil |
||||
|
from pathlib import Path |
||||
|
from typing import Annotated |
||||
|
from uuid import uuid4 |
||||
|
|
||||
|
from fastapi import FastAPI, File, HTTPException, UploadFile |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
UPLOAD_DIR = Path("uploaded_files") |
||||
|
UPLOAD_DIR.mkdir(exist_ok=True) |
||||
|
|
||||
|
|
||||
|
@app.post("/upload-product-images/") |
||||
|
async def upload_product_images( |
||||
|
files: Annotated[list[UploadFile], File(description="Product images")], |
||||
|
): |
||||
|
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
||||
|
max_size = 5 * 1024 * 1024 # 5MB |
||||
|
|
||||
|
if len(files) > 10: |
||||
|
raise HTTPException(status_code=400, detail="Too many files") |
||||
|
|
||||
|
saved = [] |
||||
|
|
||||
|
for file in files: |
||||
|
if file.content_type not in allowed_types: |
||||
|
raise HTTPException( |
||||
|
status_code=400, |
||||
|
detail=f"Invalid file type: {file.content_type}", |
||||
|
) |
||||
|
|
||||
|
contents = await file.read() |
||||
|
if len(contents) > max_size: |
||||
|
raise HTTPException( |
||||
|
status_code=400, detail=f"File too large: {file.filename}" |
||||
|
) |
||||
|
|
||||
|
file_ext = Path(file.filename).suffix |
||||
|
unique_name = f"{uuid4()}{file_ext}" |
||||
|
file_path = UPLOAD_DIR / unique_name |
||||
|
|
||||
|
await file.seek(0) |
||||
|
with file_path.open("wb") as buffer: |
||||
|
shutil.copyfileobj(file.file, buffer) |
||||
|
|
||||
|
saved.append( |
||||
|
{ |
||||
|
"filename": file.filename, |
||||
|
"saved_as": unique_name, |
||||
|
"size": len(contents), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return {"uploaded": len(saved), "files": saved} |
||||
@ -0,0 +1,87 @@ |
|||||
|
import importlib |
||||
|
import io |
||||
|
|
||||
|
import pytest |
||||
|
from fastapi import FastAPI |
||||
|
from fastapi.testclient import TestClient |
||||
|
|
||||
|
from ...utils import needs_py39, needs_py310 |
||||
|
|
||||
|
|
||||
|
@pytest.fixture( |
||||
|
name="app", |
||||
|
params=[ |
||||
|
"tutorial004", |
||||
|
pytest.param("tutorial004_an_py39", marks=needs_py39), |
||||
|
pytest.param("tutorial004_an_py310", marks=needs_py310), |
||||
|
], |
||||
|
) |
||||
|
def get_app(request: pytest.FixtureRequest): |
||||
|
mod = importlib.import_module(f"docs_src.request_files.{request.param}") |
||||
|
|
||||
|
return mod.app |
||||
|
|
||||
|
|
||||
|
@pytest.fixture(name="client") |
||||
|
def get_client(app: FastAPI): |
||||
|
client = TestClient(app) |
||||
|
return client |
||||
|
|
||||
|
|
||||
|
def test_post_upload_images_valid(client: TestClient): |
||||
|
# Create fake image files |
||||
|
file1 = ("test1.jpg", io.BytesIO(b"fake image content"), "image/jpeg") |
||||
|
file2 = ("test2.png", io.BytesIO(b"another fake image"), "image/png") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-images/", |
||||
|
files=[ |
||||
|
("files", file1), |
||||
|
("files", file2), |
||||
|
], |
||||
|
) |
||||
|
assert response.status_code == 200, response.text |
||||
|
data = response.json() |
||||
|
assert data["uploaded"] == 2 |
||||
|
assert len(data["files"]) == 2 |
||||
|
assert data["files"][0]["filename"] == "test1.jpg" |
||||
|
assert data["files"][0]["content_type"] == "image/jpeg" |
||||
|
assert data["files"][1]["filename"] == "test2.png" |
||||
|
assert data["files"][1]["content_type"] == "image/png" |
||||
|
|
||||
|
|
||||
|
def test_post_upload_images_invalid_type(client: TestClient): |
||||
|
# Upload a non-image file |
||||
|
file1 = ("test.txt", io.BytesIO(b"text content"), "text/plain") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-images/", |
||||
|
files=[("files", file1)], |
||||
|
) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "Invalid file type" in response.json()["detail"] |
||||
|
|
||||
|
|
||||
|
def test_post_upload_images_too_large(client: TestClient): |
||||
|
# Create a file larger than 5MB |
||||
|
large_content = b"x" * (6 * 1024 * 1024) # 6MB |
||||
|
file1 = ("large.jpg", io.BytesIO(large_content), "image/jpeg") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-images/", |
||||
|
files=[("files", file1)], |
||||
|
) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "too large" in response.json()["detail"].lower() |
||||
|
|
||||
|
|
||||
|
def test_post_upload_images_too_many_files(client: TestClient): |
||||
|
# Try to upload 11 files (max is 10) |
||||
|
files = [ |
||||
|
("files", (f"test{i}.jpg", io.BytesIO(b"content"), "image/jpeg")) |
||||
|
for i in range(11) |
||||
|
] |
||||
|
|
||||
|
response = client.post("/upload-images/", files=files) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "Too many files" in response.json()["detail"] |
||||
@ -0,0 +1,88 @@ |
|||||
|
import importlib |
||||
|
import io |
||||
|
|
||||
|
import pytest |
||||
|
from fastapi import FastAPI |
||||
|
from fastapi.testclient import TestClient |
||||
|
|
||||
|
from ...utils import needs_py39, needs_py310 |
||||
|
|
||||
|
|
||||
|
@pytest.fixture( |
||||
|
name="app", |
||||
|
params=[ |
||||
|
"tutorial005", |
||||
|
pytest.param("tutorial005_an_py39", marks=needs_py39), |
||||
|
pytest.param("tutorial005_an_py310", marks=needs_py310), |
||||
|
], |
||||
|
) |
||||
|
def get_app(request: pytest.FixtureRequest): |
||||
|
mod = importlib.import_module(f"docs_src.request_files.{request.param}") |
||||
|
|
||||
|
return mod.app |
||||
|
|
||||
|
|
||||
|
@pytest.fixture(name="client") |
||||
|
def get_client(app: FastAPI): |
||||
|
client = TestClient(app) |
||||
|
return client |
||||
|
|
||||
|
|
||||
|
def test_post_upload_product_images_valid(tmp_path, client: TestClient): |
||||
|
# Create fake image files |
||||
|
file1 = ("product1.jpg", io.BytesIO(b"fake image content"), "image/jpeg") |
||||
|
file2 = ("product2.png", io.BytesIO(b"another fake image"), "image/png") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-product-images/", |
||||
|
files=[ |
||||
|
("files", file1), |
||||
|
("files", file2), |
||||
|
], |
||||
|
) |
||||
|
assert response.status_code == 200, response.text |
||||
|
data = response.json() |
||||
|
assert data["uploaded"] == 2 |
||||
|
assert len(data["files"]) == 2 |
||||
|
assert data["files"][0]["filename"] == "product1.jpg" |
||||
|
assert data["files"][1]["filename"] == "product2.png" |
||||
|
# Check that saved_as is a UUID-like string |
||||
|
assert len(data["files"][0]["saved_as"]) > 30 |
||||
|
assert len(data["files"][1]["saved_as"]) > 30 |
||||
|
|
||||
|
|
||||
|
def test_post_upload_product_images_invalid_type(client: TestClient): |
||||
|
# Upload a non-image file |
||||
|
file1 = ("test.txt", io.BytesIO(b"text content"), "text/plain") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-product-images/", |
||||
|
files=[("files", file1)], |
||||
|
) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "Invalid file type" in response.json()["detail"] |
||||
|
|
||||
|
|
||||
|
def test_post_upload_product_images_too_large(client: TestClient): |
||||
|
# Create a file larger than 5MB |
||||
|
large_content = b"x" * (6 * 1024 * 1024) # 6MB |
||||
|
file1 = ("large.jpg", io.BytesIO(large_content), "image/jpeg") |
||||
|
|
||||
|
response = client.post( |
||||
|
"/upload-product-images/", |
||||
|
files=[("files", file1)], |
||||
|
) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "too large" in response.json()["detail"].lower() |
||||
|
|
||||
|
|
||||
|
def test_post_upload_product_images_too_many_files(client: TestClient): |
||||
|
# Try to upload 11 files (max is 10) |
||||
|
files = [ |
||||
|
("files", (f"product{i}.jpg", io.BytesIO(b"content"), "image/jpeg")) |
||||
|
for i in range(11) |
||||
|
] |
||||
|
|
||||
|
response = client.post("/upload-product-images/", files=files) |
||||
|
assert response.status_code == 400, response.text |
||||
|
assert "Too many files" in response.json()["detail"] |
||||
Loading…
Reference in new issue