tenants2fast-fastapi 0.1.0__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.
- tenants2fast_fastapi-0.1.0/LICENSE +21 -0
- tenants2fast_fastapi-0.1.0/MANIFEST.in +8 -0
- tenants2fast_fastapi-0.1.0/PKG-INFO +181 -0
- tenants2fast_fastapi-0.1.0/README.md +133 -0
- tenants2fast_fastapi-0.1.0/examples/basic_usage.py +57 -0
- tenants2fast_fastapi-0.1.0/pyproject.toml +78 -0
- tenants2fast_fastapi-0.1.0/setup.cfg +4 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/__init__.py +47 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/__version__.py +1 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/databases/__init__.py +13 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/databases/tenant_db_factory.py +198 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/dependencies/__init__.py +25 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/dependencies/tenant_context.py +119 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/dependencies/tenant_rbac.py +160 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/middleware/__init__.py +5 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/middleware/tenant_middleware.py +123 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/__init__.py +30 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/assignments_model.py +48 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/bases.py +25 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/permission_category_model.py +12 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/permission_model.py +14 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/role_model.py +14 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/route_model.py +14 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/tenant_model.py +35 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/tenant_user_model.py +19 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/models/user_tenant_model.py +22 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/routers/__init__.py +24 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/routers/tenant_permissions_router.py +57 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/routers/tenant_roles_router.py +90 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/routers/tenant_users_router.py +106 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/routers/tenants_router.py +142 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/__init__.py +40 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/rbac/__init__.py +33 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/rbac/permission_schema.py +32 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/rbac/role_schema.py +16 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/rbac/user_schema.py +37 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/schemas/tenant_schema.py +65 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/__init__.py +43 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_access_service.py +140 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_permission_service.py +145 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_rbac_seeder.py +66 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_role_service.py +146 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_service.py +202 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/services/tenant_user_service.py +144 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/settings.py +68 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/utils/__init__.py +17 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/utils/models_loader.py +25 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/utils/tenant_cache.py +118 -0
- tenants2fast_fastapi-0.1.0/src/tenant2fast_fastapi/utils/tenant_migrations.py +107 -0
- tenants2fast_fastapi-0.1.0/src/tenants2fast_fastapi.egg-info/PKG-INFO +181 -0
- tenants2fast_fastapi-0.1.0/src/tenants2fast_fastapi.egg-info/SOURCES.txt +62 -0
- tenants2fast_fastapi-0.1.0/src/tenants2fast_fastapi.egg-info/dependency_links.txt +1 -0
- tenants2fast_fastapi-0.1.0/src/tenants2fast_fastapi.egg-info/requires.txt +1 -0
- tenants2fast_fastapi-0.1.0/src/tenants2fast_fastapi.egg-info/top_level.txt +1 -0
- tenants2fast_fastapi-0.1.0/tests/test_get_current_tenant_user.py +46 -0
- tenants2fast_fastapi-0.1.0/tests/test_has_tenant_permission.py +135 -0
- tenants2fast_fastapi-0.1.0/tests/test_has_tenant_role.py +72 -0
- tenants2fast_fastapi-0.1.0/tests/test_middleware.py +92 -0
- tenants2fast_fastapi-0.1.0/tests/test_models.py +91 -0
- tenants2fast_fastapi-0.1.0/tests/test_package.py +56 -0
- tenants2fast_fastapi-0.1.0/tests/test_schema_propagation.py +69 -0
- tenants2fast_fastapi-0.1.0/tests/test_seeder.py +58 -0
- tenants2fast_fastapi-0.1.0/tests/test_tenant_base_model.py +66 -0
- tenants2fast_fastapi-0.1.0/tests/test_tenant_provisioning.py +65 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Angel Daniel Sanchez Castillo
|
|
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.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tenants2fast-fastapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multi-tenancy management module for FastAPI with tenant isolation and permission-aware middleware
|
|
5
|
+
Author-email: Angel Daniel Sanchez Castillo <angeldaniel.sanchezcastillo@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Angel Daniel Sanchez Castillo
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi
|
|
29
|
+
Project-URL: Documentation, https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi/tree/main/docs
|
|
30
|
+
Project-URL: Repository, https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi
|
|
31
|
+
Project-URL: Issues, https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi/issues
|
|
32
|
+
Keywords: fastapi,multitenancy,tenants,sqlmodel,middleware,rbac
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Framework :: FastAPI
|
|
42
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
43
|
+
Requires-Python: >=3.10
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
License-File: LICENSE
|
|
46
|
+
Requires-Dist: permissions2fast-fastapi>=0.5.1
|
|
47
|
+
Dynamic: license-file
|
|
48
|
+
|
|
49
|
+
# tenants2fast-fastapi
|
|
50
|
+
|
|
51
|
+
🏢 **Multi-tenancy management for FastAPI** — tenant isolation, JWT-aware middleware, and permission-gated endpoints, all wired up in minutes.
|
|
52
|
+
|
|
53
|
+
Part of the **\*2fast-fastapi** ecosystem: [oauth2fast-fastapi](https://github.com/AngelDanielSanchezCastillo/oauth2fast-fastapi) → [permissions2fast-fastapi](https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi) → **tenants2fast-fastapi**.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- 🔐 **JWT-aware `TenantMiddleware`** — extracts user from Bearer token and sets tenant context automatically on every request
|
|
60
|
+
- 🏗️ **Isolated tenant databases** — each tenant gets its own PostgreSQL database, created and initialized at runtime
|
|
61
|
+
- 🗂️ **`Tenant` and `UserTenant` SQLModel models** — ready-to-use ORM models with audit timestamps
|
|
62
|
+
- ⚡ **Redis caching** — tenant data and user permissions are cached via `permissions2fast-fastapi`
|
|
63
|
+
- 🔒 **`require_permission` dependency** — guard any route with a single line using the RBAC system from `permissions2fast-fastapi`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install tenants2fast-fastapi
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Or with `uv`:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
uv add tenants2fast-fastapi
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from fastapi import Depends, FastAPI
|
|
85
|
+
from tenant2fast_fastapi import (
|
|
86
|
+
TenantMiddleware,
|
|
87
|
+
get_current_tenant,
|
|
88
|
+
get_current_user,
|
|
89
|
+
require_permission,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
app = FastAPI()
|
|
93
|
+
|
|
94
|
+
# 1. Register the middleware
|
|
95
|
+
app.add_middleware(TenantMiddleware)
|
|
96
|
+
|
|
97
|
+
# 2. Use dependencies in your endpoints
|
|
98
|
+
@app.get("/me/tenant")
|
|
99
|
+
async def my_tenant(tenant=Depends(get_current_tenant)):
|
|
100
|
+
return {"name": tenant.name, "slug": tenant.slug}
|
|
101
|
+
|
|
102
|
+
@app.get("/reports", dependencies=[Depends(require_permission("/reports", "GET"))])
|
|
103
|
+
async def reports(user=Depends(get_current_user)):
|
|
104
|
+
return {"user": user.email}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
See [`examples/basic_usage.py`](examples/basic_usage.py) for a more complete example.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Configuration
|
|
112
|
+
|
|
113
|
+
All settings use the `TENANT_` prefix and can be provided via environment variables or a `.env` file.
|
|
114
|
+
|
|
115
|
+
| Variable | Default | Description |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `TENANT_DB_PREFIX` | `tenant_` | Prefix for per-tenant database names |
|
|
118
|
+
| `TENANT_SUPERUSER_DB__HOSTNAME` | `localhost` | PG host for superuser operations |
|
|
119
|
+
| `TENANT_SUPERUSER_DB__PORT` | `5432` | PG port |
|
|
120
|
+
| `TENANT_SUPERUSER_DB__USERNAME` | `postgres` | PG superuser username |
|
|
121
|
+
| `TENANT_SUPERUSER_DB__PASSWORD` | `postgres` | PG superuser password |
|
|
122
|
+
| `TENANT_SUPERUSER_DB__NAME` | `postgres` | Default DB for superuser connection |
|
|
123
|
+
| `TENANT_MAX_TENANT_CONNECTIONS` | `5` | Connection pool size per tenant |
|
|
124
|
+
|
|
125
|
+
In addition, all variables required by `oauth2fast-fastapi` (JWT, DB connections, mail) and `permissions2fast-fastapi` (Redis) must be set — see their respective READMEs.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Public API
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from tenant2fast_fastapi import (
|
|
133
|
+
Tenant, # SQLModel ORM model (table: tenants)
|
|
134
|
+
UserTenant, # Many-to-many User ↔ Tenant (table: user_tenants)
|
|
135
|
+
TenantMiddleware, # Starlette BaseHTTPMiddleware
|
|
136
|
+
get_current_tenant, # FastAPI dependency → Tenant
|
|
137
|
+
get_current_user, # FastAPI dependency → User (from oauth2fast-fastapi)
|
|
138
|
+
require_permission, # Dependency factory → checks RBAC + cache
|
|
139
|
+
create_tenant_database, # async — creates a PG database for a tenant
|
|
140
|
+
get_tenant_engine, # returns (cached) AsyncEngine for a tenant DB
|
|
141
|
+
initialize_tenant_schema, # async — runs SQLModel.metadata.create_all on tenant DB
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Clone and install in editable mode with dev + test dependencies
|
|
151
|
+
git clone https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi
|
|
152
|
+
cd tenants2fast-fastapi
|
|
153
|
+
uv sync --group dev --group test
|
|
154
|
+
|
|
155
|
+
# Copy .env and adjust to your local setup
|
|
156
|
+
cp .env .env.local # or just edit .env directly
|
|
157
|
+
|
|
158
|
+
# Run tests (requires PostgreSQL + Redis)
|
|
159
|
+
uv run pytest tests/ -v
|
|
160
|
+
|
|
161
|
+
# Build distribution
|
|
162
|
+
uv build
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Related Packages
|
|
168
|
+
|
|
169
|
+
| Package | PyPI | Purpose |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `log2fast-fastapi` | [](https://pypi.org/project/log2fast-fastapi/) | Structured logging |
|
|
172
|
+
| `pgsqlasync2fast-fastapi` | [](https://pypi.org/project/pgsqlasync2fast-fastapi/) | Async PostgreSQL connection manager |
|
|
173
|
+
| `mailing2fast-fastapi` | [](https://pypi.org/project/mailing2fast-fastapi/) | SMTP email sender |
|
|
174
|
+
| `oauth2fast-fastapi` | [](https://pypi.org/project/oauth2fast-fastapi/) | JWT Auth + User management |
|
|
175
|
+
| `permissions2fast-fastapi` | [](https://pypi.org/project/permissions2fast-fastapi/) | RBAC + Redis permission cache |
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT © [Angel Daniel Sanchez Castillo](https://github.com/AngelDanielSanchezCastillo)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# tenants2fast-fastapi
|
|
2
|
+
|
|
3
|
+
🏢 **Multi-tenancy management for FastAPI** — tenant isolation, JWT-aware middleware, and permission-gated endpoints, all wired up in minutes.
|
|
4
|
+
|
|
5
|
+
Part of the **\*2fast-fastapi** ecosystem: [oauth2fast-fastapi](https://github.com/AngelDanielSanchezCastillo/oauth2fast-fastapi) → [permissions2fast-fastapi](https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi) → **tenants2fast-fastapi**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🔐 **JWT-aware `TenantMiddleware`** — extracts user from Bearer token and sets tenant context automatically on every request
|
|
12
|
+
- 🏗️ **Isolated tenant databases** — each tenant gets its own PostgreSQL database, created and initialized at runtime
|
|
13
|
+
- 🗂️ **`Tenant` and `UserTenant` SQLModel models** — ready-to-use ORM models with audit timestamps
|
|
14
|
+
- ⚡ **Redis caching** — tenant data and user permissions are cached via `permissions2fast-fastapi`
|
|
15
|
+
- 🔒 **`require_permission` dependency** — guard any route with a single line using the RBAC system from `permissions2fast-fastapi`
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install tenants2fast-fastapi
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or with `uv`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add tenants2fast-fastapi
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from fastapi import Depends, FastAPI
|
|
37
|
+
from tenant2fast_fastapi import (
|
|
38
|
+
TenantMiddleware,
|
|
39
|
+
get_current_tenant,
|
|
40
|
+
get_current_user,
|
|
41
|
+
require_permission,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
app = FastAPI()
|
|
45
|
+
|
|
46
|
+
# 1. Register the middleware
|
|
47
|
+
app.add_middleware(TenantMiddleware)
|
|
48
|
+
|
|
49
|
+
# 2. Use dependencies in your endpoints
|
|
50
|
+
@app.get("/me/tenant")
|
|
51
|
+
async def my_tenant(tenant=Depends(get_current_tenant)):
|
|
52
|
+
return {"name": tenant.name, "slug": tenant.slug}
|
|
53
|
+
|
|
54
|
+
@app.get("/reports", dependencies=[Depends(require_permission("/reports", "GET"))])
|
|
55
|
+
async def reports(user=Depends(get_current_user)):
|
|
56
|
+
return {"user": user.email}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
See [`examples/basic_usage.py`](examples/basic_usage.py) for a more complete example.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
All settings use the `TENANT_` prefix and can be provided via environment variables or a `.env` file.
|
|
66
|
+
|
|
67
|
+
| Variable | Default | Description |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `TENANT_DB_PREFIX` | `tenant_` | Prefix for per-tenant database names |
|
|
70
|
+
| `TENANT_SUPERUSER_DB__HOSTNAME` | `localhost` | PG host for superuser operations |
|
|
71
|
+
| `TENANT_SUPERUSER_DB__PORT` | `5432` | PG port |
|
|
72
|
+
| `TENANT_SUPERUSER_DB__USERNAME` | `postgres` | PG superuser username |
|
|
73
|
+
| `TENANT_SUPERUSER_DB__PASSWORD` | `postgres` | PG superuser password |
|
|
74
|
+
| `TENANT_SUPERUSER_DB__NAME` | `postgres` | Default DB for superuser connection |
|
|
75
|
+
| `TENANT_MAX_TENANT_CONNECTIONS` | `5` | Connection pool size per tenant |
|
|
76
|
+
|
|
77
|
+
In addition, all variables required by `oauth2fast-fastapi` (JWT, DB connections, mail) and `permissions2fast-fastapi` (Redis) must be set — see their respective READMEs.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Public API
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from tenant2fast_fastapi import (
|
|
85
|
+
Tenant, # SQLModel ORM model (table: tenants)
|
|
86
|
+
UserTenant, # Many-to-many User ↔ Tenant (table: user_tenants)
|
|
87
|
+
TenantMiddleware, # Starlette BaseHTTPMiddleware
|
|
88
|
+
get_current_tenant, # FastAPI dependency → Tenant
|
|
89
|
+
get_current_user, # FastAPI dependency → User (from oauth2fast-fastapi)
|
|
90
|
+
require_permission, # Dependency factory → checks RBAC + cache
|
|
91
|
+
create_tenant_database, # async — creates a PG database for a tenant
|
|
92
|
+
get_tenant_engine, # returns (cached) AsyncEngine for a tenant DB
|
|
93
|
+
initialize_tenant_schema, # async — runs SQLModel.metadata.create_all on tenant DB
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Clone and install in editable mode with dev + test dependencies
|
|
103
|
+
git clone https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi
|
|
104
|
+
cd tenants2fast-fastapi
|
|
105
|
+
uv sync --group dev --group test
|
|
106
|
+
|
|
107
|
+
# Copy .env and adjust to your local setup
|
|
108
|
+
cp .env .env.local # or just edit .env directly
|
|
109
|
+
|
|
110
|
+
# Run tests (requires PostgreSQL + Redis)
|
|
111
|
+
uv run pytest tests/ -v
|
|
112
|
+
|
|
113
|
+
# Build distribution
|
|
114
|
+
uv build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Related Packages
|
|
120
|
+
|
|
121
|
+
| Package | PyPI | Purpose |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `log2fast-fastapi` | [](https://pypi.org/project/log2fast-fastapi/) | Structured logging |
|
|
124
|
+
| `pgsqlasync2fast-fastapi` | [](https://pypi.org/project/pgsqlasync2fast-fastapi/) | Async PostgreSQL connection manager |
|
|
125
|
+
| `mailing2fast-fastapi` | [](https://pypi.org/project/mailing2fast-fastapi/) | SMTP email sender |
|
|
126
|
+
| `oauth2fast-fastapi` | [](https://pypi.org/project/oauth2fast-fastapi/) | JWT Auth + User management |
|
|
127
|
+
| `permissions2fast-fastapi` | [](https://pypi.org/project/permissions2fast-fastapi/) | RBAC + Redis permission cache |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT © [Angel Daniel Sanchez Castillo](https://github.com/AngelDanielSanchezCastillo)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
basic_usage.py – minimal example of tenants2fast-fastapi integration.
|
|
3
|
+
|
|
4
|
+
Demonstrates how to:
|
|
5
|
+
1. Add TenantMiddleware to a FastAPI app
|
|
6
|
+
2. Use get_current_tenant and get_current_user as dependencies
|
|
7
|
+
3. Use require_permission to guard routes
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from fastapi import Depends, FastAPI
|
|
11
|
+
|
|
12
|
+
from tenant2fast_fastapi import (
|
|
13
|
+
TenantMiddleware,
|
|
14
|
+
get_current_tenant,
|
|
15
|
+
get_current_user,
|
|
16
|
+
require_permission,
|
|
17
|
+
)
|
|
18
|
+
from tenant2fast_fastapi.models.tenant_model import Tenant2Read
|
|
19
|
+
|
|
20
|
+
app = FastAPI(title="tenants2fast-fastapi Example")
|
|
21
|
+
|
|
22
|
+
# ── Register the tenant middleware ────────────────────────────────────────────
|
|
23
|
+
# Intercepts every request, decodes the JWT, and sets the tenant + user context
|
|
24
|
+
# before the request reaches the endpoint.
|
|
25
|
+
app.add_middleware(TenantMiddleware)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ── Protected endpoints ───────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
@app.get("/me/tenant", response_model=Tenant2Read)
|
|
31
|
+
async def get_my_tenant(tenant=Depends(get_current_tenant)):
|
|
32
|
+
"""Return the tenant for the authenticated user."""
|
|
33
|
+
return tenant
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.get("/me")
|
|
37
|
+
async def get_me(user=Depends(get_current_user)):
|
|
38
|
+
"""Return basic info about the authenticated user."""
|
|
39
|
+
return {"id": user.id, "email": user.email}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@app.get(
|
|
43
|
+
"/reports",
|
|
44
|
+
dependencies=[Depends(require_permission("/reports", "GET"))],
|
|
45
|
+
)
|
|
46
|
+
async def get_reports(user=Depends(get_current_user)):
|
|
47
|
+
"""
|
|
48
|
+
Permission-gated endpoint.
|
|
49
|
+
The user must have an explicit permission or a role that grants GET /reports.
|
|
50
|
+
"""
|
|
51
|
+
return {"message": f"Hello {user.email}, here are your reports."}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
import uvicorn
|
|
56
|
+
|
|
57
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tenants2fast-fastapi"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Multi-tenancy management module for FastAPI with tenant isolation and permission-aware middleware"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {file = "LICENSE"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Angel Daniel Sanchez Castillo", email = "angeldaniel.sanchezcastillo@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["fastapi", "multitenancy", "tenants", "sqlmodel", "middleware", "rbac"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Framework :: FastAPI",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
# Pulls in pgsqlasync2fast-fastapi, mailing2fast-fastapi,
|
|
31
|
+
# log2fast-fastapi, sqlmodel, fastapi, pydantic, etc. transitively.
|
|
32
|
+
"permissions2fast-fastapi>=0.5.1",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"black",
|
|
38
|
+
"ruff",
|
|
39
|
+
"mypy>=1.0.0",
|
|
40
|
+
"pre-commit",
|
|
41
|
+
"build",
|
|
42
|
+
"twine",
|
|
43
|
+
]
|
|
44
|
+
test = [
|
|
45
|
+
"pytest>=7.0.0",
|
|
46
|
+
"pytest-asyncio>=0.21.0",
|
|
47
|
+
"pytest-cov>=4.0.0",
|
|
48
|
+
"httpx>=0.24.0",
|
|
49
|
+
"python-dotenv>=1.0.0",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
Homepage = "https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi"
|
|
54
|
+
Documentation = "https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi/tree/main/docs"
|
|
55
|
+
Repository = "https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi"
|
|
56
|
+
Issues = "https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi/issues"
|
|
57
|
+
|
|
58
|
+
[tool.setuptools]
|
|
59
|
+
package-dir = {"" = "src"}
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.packages.find]
|
|
62
|
+
where = ["src"]
|
|
63
|
+
include = ["tenant2fast_fastapi*"]
|
|
64
|
+
|
|
65
|
+
[tool.pytest.ini_options]
|
|
66
|
+
testpaths = ["tests"]
|
|
67
|
+
python_files = ["test_*.py"]
|
|
68
|
+
python_classes = ["Test*"]
|
|
69
|
+
python_functions = ["test_*"]
|
|
70
|
+
asyncio_mode = "auto"
|
|
71
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
72
|
+
asyncio_default_test_loop_scope = "session"
|
|
73
|
+
|
|
74
|
+
[tool.mypy]
|
|
75
|
+
python_version = "3.10"
|
|
76
|
+
warn_return_any = true
|
|
77
|
+
warn_unused_configs = true
|
|
78
|
+
disallow_untyped_defs = false
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tenant2fast-fastapi
|
|
3
|
+
|
|
4
|
+
Multi-tenancy system for FastAPI applications.
|
|
5
|
+
Provides tenant management, user-tenant relationships, and tenant isolation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .__version__ import __version__
|
|
9
|
+
from .models.tenant_model import Tenant, TenantRead
|
|
10
|
+
from .middleware.tenant_middleware import TenantMiddleware
|
|
11
|
+
from .databases.tenant_db_factory import (
|
|
12
|
+
create_tenant_database,
|
|
13
|
+
get_tenant_engine,
|
|
14
|
+
initialize_tenant_schema,
|
|
15
|
+
)
|
|
16
|
+
from .dependencies import (
|
|
17
|
+
get_current_tenant,
|
|
18
|
+
get_current_user,
|
|
19
|
+
has_tenant_permission,
|
|
20
|
+
has_tenant_role,
|
|
21
|
+
get_current_tenant_user,
|
|
22
|
+
load_tenant_by_id,
|
|
23
|
+
get_tenant_context,
|
|
24
|
+
get_user_context,
|
|
25
|
+
set_tenant_context,
|
|
26
|
+
set_user_context,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"__version__",
|
|
31
|
+
"Tenant",
|
|
32
|
+
"TenantRead",
|
|
33
|
+
"TenantMiddleware",
|
|
34
|
+
"get_current_tenant",
|
|
35
|
+
"get_current_user",
|
|
36
|
+
"has_tenant_permission",
|
|
37
|
+
"has_tenant_role",
|
|
38
|
+
"get_current_tenant_user",
|
|
39
|
+
"load_tenant_by_id",
|
|
40
|
+
"get_tenant_context",
|
|
41
|
+
"get_user_context",
|
|
42
|
+
"set_tenant_context",
|
|
43
|
+
"set_user_context",
|
|
44
|
+
"create_tenant_database",
|
|
45
|
+
"get_tenant_engine",
|
|
46
|
+
"initialize_tenant_schema",
|
|
47
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Database utilities for tenant2fast-fastapi"""
|
|
2
|
+
|
|
3
|
+
from .tenant_db_factory import (
|
|
4
|
+
create_tenant_database,
|
|
5
|
+
delete_tenant_database,
|
|
6
|
+
initialize_tenant_schema,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"create_tenant_database",
|
|
11
|
+
"delete_tenant_database",
|
|
12
|
+
"initialize_tenant_schema",
|
|
13
|
+
]
|