Хотите загрузить содержимое файла на клиенте или загрузить напрямую?
Чтобы загрузить напрямую, используйте заголовок Content-Disposition
в ответе bottle.
Вот пример:
from bottle import LocalResponse, route
@route('/project/download')
def download_projects_result_file():
with open('/tmp/proj_category.csv') as file:
file.seek(0)
byte_data = file.read()
response = LocalResponse(
body=byte_data,
headers={
"Content-Disposition": "attachment; filename='filename.csv'",
"Content-Type": "text/csv",
}
)
return response