tuspyserver 2.2.2__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.3
2
+ Name: tuspyserver
3
+ Version: 3.0.1
4
+ Summary: A Python tus server implementation as a FastAPI router
5
+ Author: Edi Hasaj
6
+ Author-email: Edi Hasaj <edi.hasaj@applifyer.com>
7
+ Requires-Dist: fastapi>=0.110.0
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+
11
+ <a href="https://pypi.org/project/tuspyserver/"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/tuspyserver" align="right"></a>
12
+
13
+ # tuspyserver
14
+
15
+ A FastAPI router implementing a [tus upload protocol](https://tus.io/) server, with optional dependency-injected hooks for post-upload processing.
16
+
17
+ Only depends on `fastapi>=0.110` and `python>=3.8`.
18
+
19
+ ## Features
20
+
21
+ * **⏸️ Resumable uploads** via TUS protocol
22
+ * **🍰 Chunked transfer** with configurable max size
23
+ * **🗃️ Metadata storage** (filename, filetype)
24
+ * **🧹 Expiration & cleanup** of old uploads (default retention: 5 days)
25
+ * **💉 Dependency injection** for seamless validation (optional)
26
+ * **📡 Comprehensive API** with *download*, *HEAD*, *DELETE*, and *OPTIONS* endpoints
27
+
28
+ ## Installation
29
+
30
+ Install the [latest release from PyPI](https://pypi.org/project/tuspyserver/):
31
+
32
+ ```bash
33
+ # with uv
34
+ uv add tuspyserver
35
+ # with poetry
36
+ poetry add tuspyserver
37
+ # with pip
38
+ pip install tuspyserver
39
+ ```
40
+
41
+ Or install directly from source:
42
+
43
+ ```bash
44
+ git clone https://github.com/edihasaj/tuspyserver
45
+ cd tuspyserver
46
+ pip install .
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ### API
52
+
53
+ The main API is a single constructor that initializes the tus router. All arguments are optional, and these are their default values:
54
+
55
+ ```python
56
+ from tuspyserver import create_tus_router
57
+
58
+ tus_router = create_tus_router(
59
+ prefix="files", # route prefix (default: 'files')
60
+ files_dir="/tmp/files", # path to store files
61
+ max_size=128_849_018_880, # max upload size in bytes (default is ~128GB)
62
+ auth=noop, # authentication dependency
63
+ days_to_keep=5, # retention period
64
+ on_upload_complete=None, # upload callback
65
+ upload_complete_dep=None, # upload callback (dependency injector)
66
+ )
67
+ ```
68
+
69
+ ### Basic setup
70
+
71
+ In your `main.py`:
72
+
73
+ ```python
74
+ from tuspyserver import create_tus_router
75
+
76
+ from fastapi import FastAPI
77
+ from fastapi.middleware.cors import CORSMiddleware
78
+ from fastapi.staticfiles import StaticFiles
79
+
80
+ import uvicorn
81
+
82
+ # initialize a FastAPI app
83
+ app = FastAPI()
84
+
85
+ # configure cross-origin middleware
86
+ app.add_middleware(
87
+ CORSMiddleware,
88
+ allow_origins=["*"],
89
+ allow_methods=["*"],
90
+ allow_headers=["*"],
91
+ expose_headers=[
92
+ "Location",
93
+ "Upload-Offset",
94
+ "Tus-Resumable",
95
+ "Tus-Version",
96
+ "Tus-Extension",
97
+ "Tus-Max-Size",
98
+ "Upload-Expires",
99
+ ],
100
+ )
101
+
102
+ # use completion hook to log uploads
103
+ def log_upload(file_path: str, metadata: dict):
104
+ print("Upload complete")
105
+ print(file_path)
106
+ print(metadata)
107
+
108
+
109
+ # mount the tus router to our
110
+ app.include_router(
111
+ create_tus_router(
112
+ files_dir="./uploads",
113
+ on_upload_complete=log_upload,
114
+ )
115
+ )
116
+ ```
117
+
118
+ >[!IMPORTANT]
119
+ >Headers must be exposed for chunked uploads to work correctly.
120
+
121
+ For a comprehensive working example, see the [tuspyserver example](#example).
122
+
123
+ ### Dependency injection
124
+
125
+ For applications using FastAPI's [dependency injection](https://fastapi.tiangolo.com/tutorial/dependencies/), you can supply a factory function that returns a callback with injected dependencies. The factory can `Depends()` on any of your services (database session, current user, etc.).
126
+
127
+ ```python
128
+ # Define a factory dependency that injects your own services
129
+ from fastapi import Depends
130
+ from your_app.dependencies import get_db, get_current_user
131
+
132
+ # factory function
133
+ def log_user_upload(
134
+ db=Depends(get_db),
135
+ current_user=Depends(get_current_user),
136
+ ) -> Callable[[str, dict], None]:
137
+ # callback function
138
+ async def handler(file_path: str, metadata: dict):
139
+ # perform validation or post-processing
140
+ await db.log_upload(current_user.id, metadata)
141
+ await process_file(file_path)
142
+ return handler
143
+
144
+ # Include router with the DI hook
145
+ app.include_router(
146
+ create_api_router(
147
+ upload_complete_dep=log_user_upload,
148
+ )
149
+ )
150
+ ```
151
+
152
+ ### Expiration & cleanup
153
+
154
+ Expired files are removed when `remove_expired_files()` is called. You can schedule it using your preferred background scheduler (e.g., `APScheduler`, `cron`).
155
+
156
+ ```python
157
+ from tuspyserver import create_tus_router
158
+
159
+ from apscheduler.schedulers.background import BackgroundScheduler
160
+
161
+ tus_router = create_tus_router(
162
+ days_to_keep = 23 # configure retention period; defaults to 5 days
163
+ )
164
+
165
+ scheduler = BackgroundScheduler()
166
+ scheduler.add_job(
167
+ lambda: tus_router.remove_expired_files(),
168
+ trigger='cron',
169
+ hour=1,
170
+ )
171
+ scheduler.start()
172
+ ```
173
+
174
+ ## Example
175
+
176
+ You can find a complete working basic example in the [examples](https://github/edihasaj/tuspyserver/tree/main/examples) folder.
177
+
178
+ The example consists of the following:
179
+
180
+ ```bash
181
+ basic.py # backend: a tus router added to a fastapi app and runs it with uvicorn
182
+ static/index.html # frontend: a simple static HTML file using uppy (based on tus-js-client)
183
+ ```
184
+
185
+ To run it, you need to install [`uv`](https://docs.astral.sh/uv/) and run:
186
+ ```bash
187
+ uv run basic.py
188
+ ```
189
+
190
+ This should launch the server, and you should now be able to test uploads by browsing to http://localhost:8000/static/index.html.
191
+
192
+ Uploaded files get placed in the `examples/uploads` folder.
193
+
194
+ ## Developing
195
+
196
+ Contributions welcome! Please open issues or PRs on [GitHub](https://github.com/edihasaj/tuspyserver).
197
+
198
+ You need [`uv`](https://docs.astral.sh/uv/) to develop the project. The project is setup as a [uv workspace](https://docs.astral.sh/uv/concepts/projects/workspaces/)
199
+ where the root is the [library](https://docs.astral.sh/uv/concepts/projects/init/#libraries) and the examples directory is an [unpackagedapplication](https://docs.astral.sh/uv/concepts/projects/init/#applications)
200
+
201
+ ### Releasing
202
+
203
+ To release the package, follow the following steps:
204
+
205
+ 1. Update the version in `pyproject.toml` using [semver](https://semver.org/)
206
+ 2. Merge PR to main or push directly to main
207
+ 3. Open a PR to merge `main` → `production`.
208
+ 4. Upon merge, CI/CD will publish to PyPI.
209
+
210
+
211
+ *© 2025 Edi Hasaj [X](https://x.com/hasajedi)*
@@ -0,0 +1,201 @@
1
+ <a href="https://pypi.org/project/tuspyserver/"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/tuspyserver" align="right"></a>
2
+
3
+ # tuspyserver
4
+
5
+ A FastAPI router implementing a [tus upload protocol](https://tus.io/) server, with optional dependency-injected hooks for post-upload processing.
6
+
7
+ Only depends on `fastapi>=0.110` and `python>=3.8`.
8
+
9
+ ## Features
10
+
11
+ * **⏸️ Resumable uploads** via TUS protocol
12
+ * **🍰 Chunked transfer** with configurable max size
13
+ * **🗃️ Metadata storage** (filename, filetype)
14
+ * **🧹 Expiration & cleanup** of old uploads (default retention: 5 days)
15
+ * **💉 Dependency injection** for seamless validation (optional)
16
+ * **📡 Comprehensive API** with *download*, *HEAD*, *DELETE*, and *OPTIONS* endpoints
17
+
18
+ ## Installation
19
+
20
+ Install the [latest release from PyPI](https://pypi.org/project/tuspyserver/):
21
+
22
+ ```bash
23
+ # with uv
24
+ uv add tuspyserver
25
+ # with poetry
26
+ poetry add tuspyserver
27
+ # with pip
28
+ pip install tuspyserver
29
+ ```
30
+
31
+ Or install directly from source:
32
+
33
+ ```bash
34
+ git clone https://github.com/edihasaj/tuspyserver
35
+ cd tuspyserver
36
+ pip install .
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### API
42
+
43
+ The main API is a single constructor that initializes the tus router. All arguments are optional, and these are their default values:
44
+
45
+ ```python
46
+ from tuspyserver import create_tus_router
47
+
48
+ tus_router = create_tus_router(
49
+ prefix="files", # route prefix (default: 'files')
50
+ files_dir="/tmp/files", # path to store files
51
+ max_size=128_849_018_880, # max upload size in bytes (default is ~128GB)
52
+ auth=noop, # authentication dependency
53
+ days_to_keep=5, # retention period
54
+ on_upload_complete=None, # upload callback
55
+ upload_complete_dep=None, # upload callback (dependency injector)
56
+ )
57
+ ```
58
+
59
+ ### Basic setup
60
+
61
+ In your `main.py`:
62
+
63
+ ```python
64
+ from tuspyserver import create_tus_router
65
+
66
+ from fastapi import FastAPI
67
+ from fastapi.middleware.cors import CORSMiddleware
68
+ from fastapi.staticfiles import StaticFiles
69
+
70
+ import uvicorn
71
+
72
+ # initialize a FastAPI app
73
+ app = FastAPI()
74
+
75
+ # configure cross-origin middleware
76
+ app.add_middleware(
77
+ CORSMiddleware,
78
+ allow_origins=["*"],
79
+ allow_methods=["*"],
80
+ allow_headers=["*"],
81
+ expose_headers=[
82
+ "Location",
83
+ "Upload-Offset",
84
+ "Tus-Resumable",
85
+ "Tus-Version",
86
+ "Tus-Extension",
87
+ "Tus-Max-Size",
88
+ "Upload-Expires",
89
+ ],
90
+ )
91
+
92
+ # use completion hook to log uploads
93
+ def log_upload(file_path: str, metadata: dict):
94
+ print("Upload complete")
95
+ print(file_path)
96
+ print(metadata)
97
+
98
+
99
+ # mount the tus router to our
100
+ app.include_router(
101
+ create_tus_router(
102
+ files_dir="./uploads",
103
+ on_upload_complete=log_upload,
104
+ )
105
+ )
106
+ ```
107
+
108
+ >[!IMPORTANT]
109
+ >Headers must be exposed for chunked uploads to work correctly.
110
+
111
+ For a comprehensive working example, see the [tuspyserver example](#example).
112
+
113
+ ### Dependency injection
114
+
115
+ For applications using FastAPI's [dependency injection](https://fastapi.tiangolo.com/tutorial/dependencies/), you can supply a factory function that returns a callback with injected dependencies. The factory can `Depends()` on any of your services (database session, current user, etc.).
116
+
117
+ ```python
118
+ # Define a factory dependency that injects your own services
119
+ from fastapi import Depends
120
+ from your_app.dependencies import get_db, get_current_user
121
+
122
+ # factory function
123
+ def log_user_upload(
124
+ db=Depends(get_db),
125
+ current_user=Depends(get_current_user),
126
+ ) -> Callable[[str, dict], None]:
127
+ # callback function
128
+ async def handler(file_path: str, metadata: dict):
129
+ # perform validation or post-processing
130
+ await db.log_upload(current_user.id, metadata)
131
+ await process_file(file_path)
132
+ return handler
133
+
134
+ # Include router with the DI hook
135
+ app.include_router(
136
+ create_api_router(
137
+ upload_complete_dep=log_user_upload,
138
+ )
139
+ )
140
+ ```
141
+
142
+ ### Expiration & cleanup
143
+
144
+ Expired files are removed when `remove_expired_files()` is called. You can schedule it using your preferred background scheduler (e.g., `APScheduler`, `cron`).
145
+
146
+ ```python
147
+ from tuspyserver import create_tus_router
148
+
149
+ from apscheduler.schedulers.background import BackgroundScheduler
150
+
151
+ tus_router = create_tus_router(
152
+ days_to_keep = 23 # configure retention period; defaults to 5 days
153
+ )
154
+
155
+ scheduler = BackgroundScheduler()
156
+ scheduler.add_job(
157
+ lambda: tus_router.remove_expired_files(),
158
+ trigger='cron',
159
+ hour=1,
160
+ )
161
+ scheduler.start()
162
+ ```
163
+
164
+ ## Example
165
+
166
+ You can find a complete working basic example in the [examples](https://github/edihasaj/tuspyserver/tree/main/examples) folder.
167
+
168
+ The example consists of the following:
169
+
170
+ ```bash
171
+ basic.py # backend: a tus router added to a fastapi app and runs it with uvicorn
172
+ static/index.html # frontend: a simple static HTML file using uppy (based on tus-js-client)
173
+ ```
174
+
175
+ To run it, you need to install [`uv`](https://docs.astral.sh/uv/) and run:
176
+ ```bash
177
+ uv run basic.py
178
+ ```
179
+
180
+ This should launch the server, and you should now be able to test uploads by browsing to http://localhost:8000/static/index.html.
181
+
182
+ Uploaded files get placed in the `examples/uploads` folder.
183
+
184
+ ## Developing
185
+
186
+ Contributions welcome! Please open issues or PRs on [GitHub](https://github.com/edihasaj/tuspyserver).
187
+
188
+ You need [`uv`](https://docs.astral.sh/uv/) to develop the project. The project is setup as a [uv workspace](https://docs.astral.sh/uv/concepts/projects/workspaces/)
189
+ where the root is the [library](https://docs.astral.sh/uv/concepts/projects/init/#libraries) and the examples directory is an [unpackagedapplication](https://docs.astral.sh/uv/concepts/projects/init/#applications)
190
+
191
+ ### Releasing
192
+
193
+ To release the package, follow the following steps:
194
+
195
+ 1. Update the version in `pyproject.toml` using [semver](https://semver.org/)
196
+ 2. Merge PR to main or push directly to main
197
+ 3. Open a PR to merge `main` → `production`.
198
+ 4. Upon merge, CI/CD will publish to PyPI.
199
+
200
+
201
+ *© 2025 Edi Hasaj [X](https://x.com/hasajedi)*
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "tuspyserver"
3
+ version = "3.0.1"
4
+ description ="A Python tus server implementation as a FastAPI router"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Edi Hasaj", email = "edi.hasaj@applifyer.com" }
8
+ ]
9
+ requires-python = ">=3.8"
10
+ dependencies = [
11
+ "fastapi>=0.110.0"
12
+ ]
13
+
14
+ [build-system]
15
+ requires = ["uv_build>=0.6,<0.7"]
16
+ build-backend = "uv_build"
17
+
18
+
19
+ [tool.uv.workspace]
20
+ members = [
21
+ "examples",
22
+ ]
@@ -0,0 +1,4 @@
1
+ from tuspyserver.router import create_tus_router
2
+ from tuspyserver.metadata import FileMetadata
3
+
4
+ __all__ = ["create_tus_router", "FileMetadata"]
File without changes
@@ -18,25 +18,26 @@ from fastapi import (
18
18
  )
19
19
  from starlette.responses import FileResponse
20
20
 
21
- from tusserver.metadata import FileMetadata
21
+ from tuspyserver.metadata import FileMetadata
22
22
 
23
23
 
24
- async def default_auth():
24
+ async def noop():
25
25
  pass
26
26
 
27
27
 
28
- def create_api_router(
28
+ def create_tus_router(
29
+ prefix: str = "files",
29
30
  files_dir="/tmp/files",
30
31
  max_size=128849018880,
31
- on_upload_complete: Optional[Callable[[str, dict], None]] = None,
32
- auth: Optional[Callable[[], None]] = default_auth,
32
+ auth: Optional[Callable[[], None]] = noop,
33
33
  days_to_keep: int = 5,
34
- prefix: str = "files",
34
+ on_upload_complete: Optional[Callable[[str, dict], None]] = None,
35
35
  upload_complete_dep: Optional[Callable[..., Callable[[str, dict], None]]] = None,
36
+ tags: Optional[list[str]] = None
36
37
  ):
37
38
  if prefix and prefix[0] == "/":
38
39
  prefix = prefix[1:]
39
- router = APIRouter(prefix=f"/{prefix}", redirect_slashes=True)
40
+ router = APIRouter(prefix=f"/{prefix}", redirect_slashes=True, tags=tags if tags else ["Tus"])
40
41
 
41
42
  tus_version = "1.0.0"
42
43
  tus_extension = (
@@ -357,10 +358,4 @@ def create_api_router(
357
358
  proto, host = _get_host_and_proto(request=request)
358
359
  return f"{proto}://{host}/{prefix}/{uuid}"
359
360
 
360
- # # Create a scheduler for deleting the files
361
- # scheduler = sched.scheduler(time.time, time.sleep)
362
- # run_time = time.mktime(time.strptime("01:00", "%H:%M"))
363
- # scheduler.enterabs(run_time, 1, remove_expired_files)
364
- # scheduler.run()
365
-
366
361
  return router
tuspyserver-2.2.2/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 Tus Server for FastAPI Python
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,183 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: tuspyserver
3
- Version: 2.2.2
4
- Summary: TUS py protocol implementation in FastAPI
5
- Home-page: https://github.com/edihasaj/tuspy-fast-api
6
- Author: Edi Hasaj
7
- Author-email: edi.hasaj@applifyer.com
8
- License: MIT
9
- Platform: any
10
- Classifier: Environment :: Web Environment
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Operating System :: OS Independent
14
- Classifier: Programming Language :: Python
15
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE
18
-
19
- # FastAPI Tus
20
-
21
- A FastAPI extension implementing the [Tus.io](https://tus.io/) upload protocol, with optional dependency-injected hooks for post-upload processing.
22
-
23
- ## Prerequisites
24
-
25
- * **Python** 3.8+
26
- * **FastAPI** 0.70+
27
- * **Starlette** (installed as FastAPI dependency)
28
-
29
- ## Installation
30
-
31
- Install the latest stable release from PyPI:
32
-
33
- ```bash
34
- pip install tuspyserver
35
- ```
36
-
37
- Or install directly from source:
38
-
39
- ```bash
40
- git clone https://github.com/edihasaj/tuspy-fast-api
41
- cd tuspy-fast-api
42
- pip install .
43
- ```
44
-
45
- ## Usage
46
-
47
- ### Basic setup
48
-
49
- In your `main.py`:
50
-
51
- ```python
52
- from fastapi import FastAPI
53
- from starlette.middleware.cors import CORSMiddleware
54
- from starlette.staticfiles import StaticFiles
55
-
56
- from tusserver.tus import create_api_router
57
-
58
- app = FastAPI()
59
- app.add_middleware(
60
- CORSMiddleware,
61
- allow_origins=["*"],
62
- allow_methods=["*"],
63
- allow_headers=["*"],
64
- expose_headers=[
65
- "Location",
66
- "Upload-Offset",
67
- "Tus-Resumable",
68
- "Tus-Version",
69
- "Tus-Extension",
70
- "Tus-Max-Size",
71
- "Upload-Expires",
72
- ],
73
- )
74
- app.mount("/static", StaticFiles(directory="static"), name="static")
75
-
76
- # Optional: define a simple completion hook
77
- def on_upload_complete(file_path: str, metadata: dict):
78
- print("Upload complete:", file_path)
79
- print("Metadata:", metadata)
80
-
81
- # Include the router
82
- app.include_router(
83
- create_api_router(
84
- files_dir="/tmp/uploads", # OPTIONAL: directory to store files
85
- max_size=128_849_018_880, # OPTIONAL: max upload size in bytes (~120GB)
86
- on_upload_complete=on_upload_complete, # OPTIONAL: callback when upload finishes
87
- prefix="files", # OPTIONAL: URL prefix (default: 'files')
88
- ),
89
- )
90
-
91
- ```
92
-
93
- ### !Warning If you include your own router then it is necessary that your app allows these Headers:
94
-
95
- ```python
96
- app.add_middleware(
97
- CORSMiddleware, (# OPTIONAL: add CORS middleware if needed)
98
- allow_origins=["*"], # OPTIONAL: allow all origins
99
- allow_methods=["*"], # OPTIONAL: allow all methods
100
- allow_headers=["*"], # OPTIONAL: allow all headers
101
- expose_headers=[ # REQUIRED: expose these headers to the client
102
- "Location",
103
- "Upload-Offset",
104
- "Tus-Resumable",
105
- "Tus-Version",
106
- "Tus-Extension",
107
- "Tus-Max-Size",
108
- "Upload-Expires",
109
- ],
110
- )
111
- ```
112
-
113
- ### Dependency‑Injected Hook (Advanced)
114
-
115
- For applications using FastAPI's dependency injection, you can supply a factory that returns a DI‑enabled callback. This factory can `Depends()` on any of your services (database session, current user, etc.).
116
-
117
- ```python
118
- # Define a factory dependency that injects your own services
119
- from fastapi import Depends
120
- from your_app.dependencies import get_db, get_current_user
121
-
122
- def get_upload_handler(
123
- db=Depends(get_db),
124
- current_user=Depends(get_current_user),
125
- ) -> Callable[[str, dict], None]:
126
- def handler(file_path: str, metadata: dict):
127
- # perform validation or post-processing
128
- db.log_upload(current_user.id, metadata)
129
- process_file(file_path)
130
- return handler
131
-
132
- # Include router with the DI hook
133
- app.include_router(
134
- create_api_router(
135
- on_upload_complete=None, # keep default
136
- upload_complete_dep=get_upload_handler, # factory dependency
137
- )
138
- )
139
- ```
140
-
141
- ### Features
142
-
143
- * **Resumable uploads** via TUS protocol
144
- * **Chunked transfer** with configurable max size
145
- * **Metadata storage** (filename, filetype)
146
- * **Expiration & cleanup** of old uploads (default retention: 5 days)
147
- * **Download**, **HEAD**, **DELETE**, and **OPTIONS** endpoints
148
- * **Optional** DI‑friendly `upload_complete_dep` for seamless integration with FastAPI
149
-
150
- ## Scheduler (Cleanup)
151
-
152
- Expired files are removed when `remove_expired_files()` is called. You can schedule it using your preferred background scheduler (e.g., `APScheduler`, `cron`).
153
-
154
- ```python
155
- from apscheduler.schedulers.background import BackgroundScheduler
156
-
157
- scheduler = BackgroundScheduler()
158
- scheduler.add_job(
159
- lambda: router.remove_expired_files(),
160
- trigger='cron',
161
- hour=1,
162
- )
163
- scheduler.start()
164
- ```
165
-
166
- ## Versioning & Publishing
167
-
168
- **Before releasing:**
169
-
170
- 1. Update the version in `setup.py`:
171
-
172
- * **Patch** for bug fixes
173
- * **Minor** for new features
174
- * **Major** for breaking changes
175
- 2. Commit and push to `main`.
176
- 3. Open a PR to merge `main` → `production`.
177
- 4. Upon merge, CI/CD will publish to PyPI.
178
-
179
- ## Contributing
180
-
181
- Contributions welcome! Please open issues or PRs on [GitHub](https://github.com/edihasaj/tuspy-fast-api).
182
-
183
- *© 2025 Edi Hasaj [X](https://x.com/hasajedi)*
@@ -1,165 +0,0 @@
1
- # FastAPI Tus
2
-
3
- A FastAPI extension implementing the [Tus.io](https://tus.io/) upload protocol, with optional dependency-injected hooks for post-upload processing.
4
-
5
- ## Prerequisites
6
-
7
- * **Python** 3.8+
8
- * **FastAPI** 0.70+
9
- * **Starlette** (installed as FastAPI dependency)
10
-
11
- ## Installation
12
-
13
- Install the latest stable release from PyPI:
14
-
15
- ```bash
16
- pip install tuspyserver
17
- ```
18
-
19
- Or install directly from source:
20
-
21
- ```bash
22
- git clone https://github.com/edihasaj/tuspy-fast-api
23
- cd tuspy-fast-api
24
- pip install .
25
- ```
26
-
27
- ## Usage
28
-
29
- ### Basic setup
30
-
31
- In your `main.py`:
32
-
33
- ```python
34
- from fastapi import FastAPI
35
- from starlette.middleware.cors import CORSMiddleware
36
- from starlette.staticfiles import StaticFiles
37
-
38
- from tusserver.tus import create_api_router
39
-
40
- app = FastAPI()
41
- app.add_middleware(
42
- CORSMiddleware,
43
- allow_origins=["*"],
44
- allow_methods=["*"],
45
- allow_headers=["*"],
46
- expose_headers=[
47
- "Location",
48
- "Upload-Offset",
49
- "Tus-Resumable",
50
- "Tus-Version",
51
- "Tus-Extension",
52
- "Tus-Max-Size",
53
- "Upload-Expires",
54
- ],
55
- )
56
- app.mount("/static", StaticFiles(directory="static"), name="static")
57
-
58
- # Optional: define a simple completion hook
59
- def on_upload_complete(file_path: str, metadata: dict):
60
- print("Upload complete:", file_path)
61
- print("Metadata:", metadata)
62
-
63
- # Include the router
64
- app.include_router(
65
- create_api_router(
66
- files_dir="/tmp/uploads", # OPTIONAL: directory to store files
67
- max_size=128_849_018_880, # OPTIONAL: max upload size in bytes (~120GB)
68
- on_upload_complete=on_upload_complete, # OPTIONAL: callback when upload finishes
69
- prefix="files", # OPTIONAL: URL prefix (default: 'files')
70
- ),
71
- )
72
-
73
- ```
74
-
75
- ### !Warning If you include your own router then it is necessary that your app allows these Headers:
76
-
77
- ```python
78
- app.add_middleware(
79
- CORSMiddleware, (# OPTIONAL: add CORS middleware if needed)
80
- allow_origins=["*"], # OPTIONAL: allow all origins
81
- allow_methods=["*"], # OPTIONAL: allow all methods
82
- allow_headers=["*"], # OPTIONAL: allow all headers
83
- expose_headers=[ # REQUIRED: expose these headers to the client
84
- "Location",
85
- "Upload-Offset",
86
- "Tus-Resumable",
87
- "Tus-Version",
88
- "Tus-Extension",
89
- "Tus-Max-Size",
90
- "Upload-Expires",
91
- ],
92
- )
93
- ```
94
-
95
- ### Dependency‑Injected Hook (Advanced)
96
-
97
- For applications using FastAPI's dependency injection, you can supply a factory that returns a DI‑enabled callback. This factory can `Depends()` on any of your services (database session, current user, etc.).
98
-
99
- ```python
100
- # Define a factory dependency that injects your own services
101
- from fastapi import Depends
102
- from your_app.dependencies import get_db, get_current_user
103
-
104
- def get_upload_handler(
105
- db=Depends(get_db),
106
- current_user=Depends(get_current_user),
107
- ) -> Callable[[str, dict], None]:
108
- def handler(file_path: str, metadata: dict):
109
- # perform validation or post-processing
110
- db.log_upload(current_user.id, metadata)
111
- process_file(file_path)
112
- return handler
113
-
114
- # Include router with the DI hook
115
- app.include_router(
116
- create_api_router(
117
- on_upload_complete=None, # keep default
118
- upload_complete_dep=get_upload_handler, # factory dependency
119
- )
120
- )
121
- ```
122
-
123
- ### Features
124
-
125
- * **Resumable uploads** via TUS protocol
126
- * **Chunked transfer** with configurable max size
127
- * **Metadata storage** (filename, filetype)
128
- * **Expiration & cleanup** of old uploads (default retention: 5 days)
129
- * **Download**, **HEAD**, **DELETE**, and **OPTIONS** endpoints
130
- * **Optional** DI‑friendly `upload_complete_dep` for seamless integration with FastAPI
131
-
132
- ## Scheduler (Cleanup)
133
-
134
- Expired files are removed when `remove_expired_files()` is called. You can schedule it using your preferred background scheduler (e.g., `APScheduler`, `cron`).
135
-
136
- ```python
137
- from apscheduler.schedulers.background import BackgroundScheduler
138
-
139
- scheduler = BackgroundScheduler()
140
- scheduler.add_job(
141
- lambda: router.remove_expired_files(),
142
- trigger='cron',
143
- hour=1,
144
- )
145
- scheduler.start()
146
- ```
147
-
148
- ## Versioning & Publishing
149
-
150
- **Before releasing:**
151
-
152
- 1. Update the version in `setup.py`:
153
-
154
- * **Patch** for bug fixes
155
- * **Minor** for new features
156
- * **Major** for breaking changes
157
- 2. Commit and push to `main`.
158
- 3. Open a PR to merge `main` → `production`.
159
- 4. Upon merge, CI/CD will publish to PyPI.
160
-
161
- ## Contributing
162
-
163
- Contributions welcome! Please open issues or PRs on [GitHub](https://github.com/edihasaj/tuspy-fast-api).
164
-
165
- *© 2025 Edi Hasaj [X](https://x.com/hasajedi)*
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
@@ -1,38 +0,0 @@
1
- """
2
- FastAPI Tus implementation
3
- -------------
4
- Implements the tus.io server-side file-upload protocol
5
- visit https://tus.io for more information
6
- """
7
-
8
- from setuptools import find_packages, setup
9
-
10
- with open("README.md", "r") as f:
11
- long_description = f.read()
12
-
13
- setup(
14
- name="tuspyserver",
15
- version="2.2.2",
16
- description="TUS py protocol implementation in FastAPI",
17
- long_description=long_description,
18
- long_description_content_type="text/markdown",
19
- author="Edi Hasaj",
20
- license="MIT",
21
- author_email="edi.hasaj@applifyer.com",
22
- url="https://github.com/edihasaj/tuspy-fast-api",
23
- packages=find_packages(),
24
- platforms="any",
25
- include_package_data=True,
26
- install_requires=[
27
- "fastapi>=0.110.0",
28
- "pydantic>=2.6.2",
29
- ],
30
- classifiers=[
31
- "Environment :: Web Environment",
32
- "Intended Audience :: Developers",
33
- "License :: OSI Approved :: MIT License",
34
- "Operating System :: OS Independent",
35
- "Programming Language :: Python",
36
- "Topic :: Software Development :: Libraries :: Python Modules",
37
- ],
38
- )
@@ -1,183 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: tuspyserver
3
- Version: 2.2.2
4
- Summary: TUS py protocol implementation in FastAPI
5
- Home-page: https://github.com/edihasaj/tuspy-fast-api
6
- Author: Edi Hasaj
7
- Author-email: edi.hasaj@applifyer.com
8
- License: MIT
9
- Platform: any
10
- Classifier: Environment :: Web Environment
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Operating System :: OS Independent
14
- Classifier: Programming Language :: Python
15
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE
18
-
19
- # FastAPI Tus
20
-
21
- A FastAPI extension implementing the [Tus.io](https://tus.io/) upload protocol, with optional dependency-injected hooks for post-upload processing.
22
-
23
- ## Prerequisites
24
-
25
- * **Python** 3.8+
26
- * **FastAPI** 0.70+
27
- * **Starlette** (installed as FastAPI dependency)
28
-
29
- ## Installation
30
-
31
- Install the latest stable release from PyPI:
32
-
33
- ```bash
34
- pip install tuspyserver
35
- ```
36
-
37
- Or install directly from source:
38
-
39
- ```bash
40
- git clone https://github.com/edihasaj/tuspy-fast-api
41
- cd tuspy-fast-api
42
- pip install .
43
- ```
44
-
45
- ## Usage
46
-
47
- ### Basic setup
48
-
49
- In your `main.py`:
50
-
51
- ```python
52
- from fastapi import FastAPI
53
- from starlette.middleware.cors import CORSMiddleware
54
- from starlette.staticfiles import StaticFiles
55
-
56
- from tusserver.tus import create_api_router
57
-
58
- app = FastAPI()
59
- app.add_middleware(
60
- CORSMiddleware,
61
- allow_origins=["*"],
62
- allow_methods=["*"],
63
- allow_headers=["*"],
64
- expose_headers=[
65
- "Location",
66
- "Upload-Offset",
67
- "Tus-Resumable",
68
- "Tus-Version",
69
- "Tus-Extension",
70
- "Tus-Max-Size",
71
- "Upload-Expires",
72
- ],
73
- )
74
- app.mount("/static", StaticFiles(directory="static"), name="static")
75
-
76
- # Optional: define a simple completion hook
77
- def on_upload_complete(file_path: str, metadata: dict):
78
- print("Upload complete:", file_path)
79
- print("Metadata:", metadata)
80
-
81
- # Include the router
82
- app.include_router(
83
- create_api_router(
84
- files_dir="/tmp/uploads", # OPTIONAL: directory to store files
85
- max_size=128_849_018_880, # OPTIONAL: max upload size in bytes (~120GB)
86
- on_upload_complete=on_upload_complete, # OPTIONAL: callback when upload finishes
87
- prefix="files", # OPTIONAL: URL prefix (default: 'files')
88
- ),
89
- )
90
-
91
- ```
92
-
93
- ### !Warning If you include your own router then it is necessary that your app allows these Headers:
94
-
95
- ```python
96
- app.add_middleware(
97
- CORSMiddleware, (# OPTIONAL: add CORS middleware if needed)
98
- allow_origins=["*"], # OPTIONAL: allow all origins
99
- allow_methods=["*"], # OPTIONAL: allow all methods
100
- allow_headers=["*"], # OPTIONAL: allow all headers
101
- expose_headers=[ # REQUIRED: expose these headers to the client
102
- "Location",
103
- "Upload-Offset",
104
- "Tus-Resumable",
105
- "Tus-Version",
106
- "Tus-Extension",
107
- "Tus-Max-Size",
108
- "Upload-Expires",
109
- ],
110
- )
111
- ```
112
-
113
- ### Dependency‑Injected Hook (Advanced)
114
-
115
- For applications using FastAPI's dependency injection, you can supply a factory that returns a DI‑enabled callback. This factory can `Depends()` on any of your services (database session, current user, etc.).
116
-
117
- ```python
118
- # Define a factory dependency that injects your own services
119
- from fastapi import Depends
120
- from your_app.dependencies import get_db, get_current_user
121
-
122
- def get_upload_handler(
123
- db=Depends(get_db),
124
- current_user=Depends(get_current_user),
125
- ) -> Callable[[str, dict], None]:
126
- def handler(file_path: str, metadata: dict):
127
- # perform validation or post-processing
128
- db.log_upload(current_user.id, metadata)
129
- process_file(file_path)
130
- return handler
131
-
132
- # Include router with the DI hook
133
- app.include_router(
134
- create_api_router(
135
- on_upload_complete=None, # keep default
136
- upload_complete_dep=get_upload_handler, # factory dependency
137
- )
138
- )
139
- ```
140
-
141
- ### Features
142
-
143
- * **Resumable uploads** via TUS protocol
144
- * **Chunked transfer** with configurable max size
145
- * **Metadata storage** (filename, filetype)
146
- * **Expiration & cleanup** of old uploads (default retention: 5 days)
147
- * **Download**, **HEAD**, **DELETE**, and **OPTIONS** endpoints
148
- * **Optional** DI‑friendly `upload_complete_dep` for seamless integration with FastAPI
149
-
150
- ## Scheduler (Cleanup)
151
-
152
- Expired files are removed when `remove_expired_files()` is called. You can schedule it using your preferred background scheduler (e.g., `APScheduler`, `cron`).
153
-
154
- ```python
155
- from apscheduler.schedulers.background import BackgroundScheduler
156
-
157
- scheduler = BackgroundScheduler()
158
- scheduler.add_job(
159
- lambda: router.remove_expired_files(),
160
- trigger='cron',
161
- hour=1,
162
- )
163
- scheduler.start()
164
- ```
165
-
166
- ## Versioning & Publishing
167
-
168
- **Before releasing:**
169
-
170
- 1. Update the version in `setup.py`:
171
-
172
- * **Patch** for bug fixes
173
- * **Minor** for new features
174
- * **Major** for breaking changes
175
- 2. Commit and push to `main`.
176
- 3. Open a PR to merge `main` → `production`.
177
- 4. Upon merge, CI/CD will publish to PyPI.
178
-
179
- ## Contributing
180
-
181
- Contributions welcome! Please open issues or PRs on [GitHub](https://github.com/edihasaj/tuspy-fast-api).
182
-
183
- *© 2025 Edi Hasaj [X](https://x.com/hasajedi)*
@@ -1,11 +0,0 @@
1
- LICENSE
2
- README.md
3
- setup.py
4
- tuspyserver.egg-info/PKG-INFO
5
- tuspyserver.egg-info/SOURCES.txt
6
- tuspyserver.egg-info/dependency_links.txt
7
- tuspyserver.egg-info/requires.txt
8
- tuspyserver.egg-info/top_level.txt
9
- tusserver/__init__.py
10
- tusserver/metadata.py
11
- tusserver/tus.py
@@ -1,2 +0,0 @@
1
- fastapi>=0.110.0
2
- pydantic>=2.6.2
@@ -1 +0,0 @@
1
- tusserver
@@ -1 +0,0 @@
1
- __version__ = "1.0.0"