future-framework 1.1.2__tar.gz → 2.0.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.
- {future_framework-1.1.2 → future_framework-2.0.0}/PKG-INFO +11 -9
- {future_framework-1.1.2 → future_framework-2.0.0}/README.md +5 -5
- future_framework-2.0.0/future/__init__.py +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/application.py +15 -9
- future_framework-2.0.0/future/authentication/Auth0Authentication.py +9 -0
- future_framework-2.0.0/future/authentication/AzureADAuthentication.py +9 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/authentication/BasicAuthentication.py +2 -2
- future_framework-2.0.0/future/authentication/KerberosAuthentication.py +9 -0
- future_framework-2.0.0/future/authentication/KeycloakAuthentication.py +9 -0
- future_framework-2.0.0/future/authentication/OAuth2Authentication.py +9 -0
- future_framework-2.0.0/future/authentication/OpenIdConnectAuthentication.py +9 -0
- future_framework-2.0.0/future/authentication/SAMLAuthentication.py +9 -0
- future_framework-2.0.0/future/authentication/__init__.py +0 -0
- future_framework-2.0.0/future/cli.py +738 -0
- future_framework-1.1.2/future/controllers/builtins.py → future_framework-2.0.0/future/controllers/DebugController.py +3 -17
- future_framework-2.0.0/future/controllers/GraphQLController.py +173 -0
- future_framework-1.1.2/future/controllers/openapi.py → future_framework-2.0.0/future/controllers/OpenAPIController.py +2 -2
- future_framework-2.0.0/future/controllers/WebSocketController.py +13 -0
- future_framework-2.0.0/future/controllers/WelcomeController.py +7 -0
- future_framework-2.0.0/future/controllers/__init__.py +0 -0
- future_framework-1.1.2/future/databases/Connections.py → future_framework-2.0.0/future/database.py +5 -5
- future_framework-1.1.2/future/databases/Clickhouse.py → future_framework-2.0.0/future/databases/ClickhouseDatabase.py +78 -56
- future_framework-2.0.0/future/databases/ElasticsearchDatabase.py +174 -0
- future_framework-1.1.2/future/databases/MongoDB.py → future_framework-2.0.0/future/databases/MongoDBDatabase.py +50 -50
- future_framework-1.1.2/future/databases/MySQL.py → future_framework-2.0.0/future/databases/MySQLDatabase.py +73 -72
- future_framework-1.1.2/future/databases/Postgres.py → future_framework-2.0.0/future/databases/PostgresDatabase.py +70 -69
- future_framework-1.1.2/future/databases/Redis.py → future_framework-2.0.0/future/databases/RedisDatabase.py +36 -36
- future_framework-1.1.2/future/databases/SQLite.py → future_framework-2.0.0/future/databases/SQLiteDatabase.py +72 -71
- future_framework-2.0.0/future/databases/__init__.py +0 -0
- future_framework-2.0.0/future/interfaces/IAuthentication.py +5 -0
- future_framework-1.1.2/future/controllers/base.py → future_framework-2.0.0/future/interfaces/IController.py +2 -1
- future_framework-1.1.2/future/databases/Database.py → future_framework-2.0.0/future/interfaces/IDatabase.py +20 -18
- future_framework-2.0.0/future/interfaces/IMiddleware.py +26 -0
- future_framework-1.1.2/future/models/model.py → future_framework-2.0.0/future/interfaces/IModel.py +53 -74
- future_framework-2.0.0/future/interfaces/IPlugin.py +5 -0
- future_framework-2.0.0/future/interfaces/ITask.py +16 -0
- future_framework-2.0.0/future/interfaces/__init__.py +0 -0
- future_framework-2.0.0/future/interfacing.py +73 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/lifespan.py +5 -14
- future_framework-2.0.0/future/middleware/BruteforcePreventionMiddleware.py +5 -0
- future_framework-2.0.0/future/middleware/CORSMiddleware.py +30 -0
- future_framework-2.0.0/future/middleware/CSRFMiddleware.py +35 -0
- future_framework-2.0.0/future/middleware/GZipMiddleware.py +25 -0
- future_framework-2.0.0/future/middleware/HTAccessConfuserMiddleware.py +5 -0
- future_framework-2.0.0/future/middleware/HeaderConfuserMiddleware.py +5 -0
- future_framework-2.0.0/future/middleware/RateLimitMiddleware.py +23 -0
- future_framework-2.0.0/future/middleware/ResponseCodeConfuserMiddleware.py +22 -0
- future_framework-2.0.0/future/middleware/SQLiConfuserMiddleware.py +5 -0
- future_framework-2.0.0/future/middleware/ScopeValidationMiddleware.py +27 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/middleware/SessionMiddleware.py +2 -2
- future_framework-2.0.0/future/middleware/TestMiddlewareRequest.py +13 -0
- future_framework-2.0.0/future/middleware/TestMiddlewareResponse.py +13 -0
- future_framework-2.0.0/future/middleware/WebServerConfuserMiddleware.py +5 -0
- future_framework-2.0.0/future/middleware/__init__.py +0 -0
- future_framework-2.0.0/future/migrations.py +312 -0
- future_framework-2.0.0/future/models/PostModel.py +13 -0
- future_framework-2.0.0/future/models/Query.py +40 -0
- future_framework-2.0.0/future/models/UserModel.py +10 -0
- future_framework-2.0.0/future/models/__init__.py +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/openapi.py +1 -1
- {future_framework-1.1.2 → future_framework-2.0.0}/future/plugins/ElasticsearchPlugin.py +93 -91
- future_framework-2.0.0/future/plugins/__init__.py +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/request.py +1 -1
- {future_framework-1.1.2 → future_framework-2.0.0}/future/response.py +20 -1
- {future_framework-1.1.2 → future_framework-2.0.0}/future/routing.py +13 -13
- future_framework-1.1.2/future/seeds/SeedGenerator.py → future_framework-2.0.0/future/seeder.py +59 -6
- future_framework-2.0.0/future/tasks/CheckDNSTask.py +21 -0
- future_framework-2.0.0/future/tasks/CheckDiskUsageTask.py +22 -0
- future_framework-2.0.0/future/tasks/CheckHttpStatusTask.py +22 -0
- future_framework-2.0.0/future/tasks/CheckMemoryUsageTask.py +20 -0
- future_framework-2.0.0/future/tasks/CheckSSHBannerTask.py +25 -0
- future_framework-2.0.0/future/tasks/CheckSystemUptimeTask.py +23 -0
- future_framework-2.0.0/future/tasks/DailyBackupTask.py +16 -0
- future_framework-2.0.0/future/tasks/SyncTaskExample.py +14 -0
- future_framework-2.0.0/future/tasks/__init__.py +0 -0
- future_framework-2.0.0/future/taskscheduler.py +135 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/types.py +1 -1
- {future_framework-1.1.2 → future_framework-2.0.0}/pyproject.toml +6 -4
- future_framework-1.1.2/future/__init__.py +0 -3
- future_framework-1.1.2/future/authentication/Auth0Authentication.py +0 -9
- future_framework-1.1.2/future/authentication/Authentication.py +0 -11
- future_framework-1.1.2/future/authentication/AzureADAuthentication.py +0 -9
- future_framework-1.1.2/future/authentication/KerberosAuthentication.py +0 -9
- future_framework-1.1.2/future/authentication/KeycloakAuthentication.py +0 -9
- future_framework-1.1.2/future/authentication/OAuth2Authentication.py +0 -9
- future_framework-1.1.2/future/authentication/OpenIdConnectAuthentication.py +0 -9
- future_framework-1.1.2/future/authentication/SAMLAuthentication.py +0 -9
- future_framework-1.1.2/future/cli/__init__.py +0 -1
- future_framework-1.1.2/future/cli/main.py +0 -607
- future_framework-1.1.2/future/cli/stubs.py +0 -114
- future_framework-1.1.2/future/controllers/__init__.py +0 -4
- future_framework-1.1.2/future/controllers/graphql.py +0 -23
- future_framework-1.1.2/future/databases/Elasticsearch.py +0 -146
- future_framework-1.1.2/future/graphql/__init__.py +0 -1
- future_framework-1.1.2/future/graphql/schema.py +0 -148
- future_framework-1.1.2/future/middleware/Middleware.py +0 -201
- future_framework-1.1.2/future/middleware/__init__.py +0 -21
- future_framework-1.1.2/future/migrations/Blueprint.py +0 -54
- future_framework-1.1.2/future/migrations/Column.py +0 -33
- future_framework-1.1.2/future/migrations/Migration.py +0 -11
- future_framework-1.1.2/future/migrations/MigrationGenerator.py +0 -137
- future_framework-1.1.2/future/migrations/Migrator.py +0 -72
- future_framework-1.1.2/future/migrations/Schema.py +0 -21
- future_framework-1.1.2/future/models/__init__.py +0 -1
- future_framework-1.1.2/future/plugins/__init__.py +0 -9
- future_framework-1.1.2/future/seeds/SeedRunner.py +0 -42
- future_framework-1.1.2/future/seeds/Seeder.py +0 -9
- future_framework-1.1.2/future/tasks/__init__.py +0 -14
- future_framework-1.1.2/future/tasks/scheduler.py +0 -267
- future_framework-1.1.2/future/testing/__init__.py +0 -1
- {future_framework-1.1.2 → future_framework-2.0.0}/LICENSE +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/exceptions.py +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/logger.py +0 -0
- {future_framework-1.1.2 → future_framework-2.0.0}/future/settings.py +0 -0
- /future_framework-1.1.2/future/testing/client.py → /future_framework-2.0.0/future/testclient.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: future-framework
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: ASGI-based framework for web APIs
|
|
5
5
|
License: LICENSE
|
|
6
6
|
License-File: LICENSE
|
|
@@ -11,14 +11,16 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: aiomysql (>=0.2.0,<0.3.0)
|
|
15
|
+
Requires-Dist: aiosqlite (>=0.21.0,<0.22.0)
|
|
16
|
+
Requires-Dist: asynch (>=0.2.5,<0.3.0)
|
|
17
|
+
Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
|
|
14
18
|
Requires-Dist: clickhouse-driver (>=0.2.11,<0.3.0)
|
|
15
|
-
Requires-Dist: elasticsearch (>=
|
|
19
|
+
Requires-Dist: elasticsearch (>=8.15.0,<9)
|
|
16
20
|
Requires-Dist: faker (>=40.0.0,<41.0.0)
|
|
17
21
|
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
18
22
|
Requires-Dist: inflection (>=0.5.1,<0.6.0)
|
|
19
|
-
Requires-Dist: psycopg2-binary (>=2.9.12,<3.0.0)
|
|
20
23
|
Requires-Dist: pymongo (>=4.17.0,<5.0.0)
|
|
21
|
-
Requires-Dist: pymysql (>=1.2.0,<2.0.0)
|
|
22
24
|
Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
|
|
23
25
|
Requires-Dist: redis (>=8.0.0,<9.0.0)
|
|
24
26
|
Requires-Dist: rich (>=15.0.0,<16.0.0)
|
|
@@ -32,11 +34,11 @@ Project-URL: Repository, https://github.com/nicolaipre/future-framework
|
|
|
32
34
|
Description-Content-Type: text/markdown
|
|
33
35
|
|
|
34
36
|
# Future
|
|
35
|
-
|
|
37
|
+
[ASGI](https://asgi.readthedocs.io/)-based framework for web APIs — routing, middleware, Active Record, migrations, seeds, OpenAPI, and interval tasks.
|
|
36
38
|
|
|
37
39
|
[](https://github.com/nicolaipre/future-framework/actions)
|
|
38
|
-
[](https://pypi.org/project/future-framework/)
|
|
41
|
+
[](https://codecov.io/gh/nicolaipre/future-framework)
|
|
40
42
|
|
|
41
43
|
## Documentation
|
|
42
44
|
Published at **[nicolaipre.github.io/future-framework](https://nicolaipre.github.io/future-framework/)**. To preview locally: `poetry install --with docs && poetry run mkdocs serve`.
|
|
@@ -52,12 +54,12 @@ Import name is `future` (`from future.application import Future`).
|
|
|
52
54
|
## Hello
|
|
53
55
|
```python
|
|
54
56
|
from future.application import Future
|
|
55
|
-
from future.
|
|
57
|
+
from future.interfaces.IController import IController
|
|
56
58
|
from future.lifespan import Lifespan
|
|
57
59
|
from future.response import Response
|
|
58
60
|
from future.routing import Get, RouteGroup
|
|
59
61
|
|
|
60
|
-
class HomeController(
|
|
62
|
+
class HomeController(IController):
|
|
61
63
|
async def index(self) -> Response:
|
|
62
64
|
return self.response.json({"ok": True})
|
|
63
65
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Future
|
|
2
|
-
|
|
2
|
+
[ASGI](https://asgi.readthedocs.io/)-based framework for web APIs — routing, middleware, Active Record, migrations, seeds, OpenAPI, and interval tasks.
|
|
3
3
|
|
|
4
4
|
[](https://github.com/nicolaipre/future-framework/actions)
|
|
5
|
-
[](https://pypi.org/project/future-framework/)
|
|
6
|
+
[](https://codecov.io/gh/nicolaipre/future-framework)
|
|
7
7
|
|
|
8
8
|
## Documentation
|
|
9
9
|
Published at **[nicolaipre.github.io/future-framework](https://nicolaipre.github.io/future-framework/)**. To preview locally: `poetry install --with docs && poetry run mkdocs serve`.
|
|
@@ -19,12 +19,12 @@ Import name is `future` (`from future.application import Future`).
|
|
|
19
19
|
## Hello
|
|
20
20
|
```python
|
|
21
21
|
from future.application import Future
|
|
22
|
-
from future.
|
|
22
|
+
from future.interfaces.IController import IController
|
|
23
23
|
from future.lifespan import Lifespan
|
|
24
24
|
from future.response import Response
|
|
25
25
|
from future.routing import Get, RouteGroup
|
|
26
26
|
|
|
27
|
-
class HomeController(
|
|
27
|
+
class HomeController(IController):
|
|
28
28
|
async def index(self) -> Response:
|
|
29
29
|
return self.response.json({"ok": True})
|
|
30
30
|
|
|
File without changes
|
|
@@ -17,7 +17,7 @@ from rich.text import Text
|
|
|
17
17
|
|
|
18
18
|
from future.exceptions import ErrorHandler, HTTPException
|
|
19
19
|
from future.logger import log
|
|
20
|
-
from future.
|
|
20
|
+
from future.interfaces.IMiddleware import IMiddleware
|
|
21
21
|
from future.openapi import get_openapi_config, is_docs_path, openapi_routes, rebuild_spec_from_routes, set_openapi_config, spec_path
|
|
22
22
|
from future.request import Request
|
|
23
23
|
from future.response import Response, WebSocketResponse
|
|
@@ -80,8 +80,8 @@ class Future:
|
|
|
80
80
|
self.config = config or {}
|
|
81
81
|
self.databases = self.config.get("DATABASES")
|
|
82
82
|
if self.databases:
|
|
83
|
-
from future.
|
|
84
|
-
|
|
83
|
+
from future.database import Database
|
|
84
|
+
Database().set_connection_details(self.databases)
|
|
85
85
|
|
|
86
86
|
domain = self.config.get("APP_DOMAIN", "")
|
|
87
87
|
|
|
@@ -133,7 +133,7 @@ class Future:
|
|
|
133
133
|
return cls, endpoint.__name__
|
|
134
134
|
return None, None
|
|
135
135
|
|
|
136
|
-
def _add_route(self, route: Route, subdomain: str = "", parent_middlewares: Optional[list[
|
|
136
|
+
def _add_route(self, route: Route, subdomain: str = "", parent_middlewares: Optional[list[IMiddleware]] = None, group: Optional[dict[str, str]] = None) -> None:
|
|
137
137
|
"""Internal method to add single routes to the application.
|
|
138
138
|
|
|
139
139
|
Args:
|
|
@@ -165,7 +165,7 @@ class Future:
|
|
|
165
165
|
group=group or {"name": "", "prefix": "", "subdomain": ""},
|
|
166
166
|
)
|
|
167
167
|
|
|
168
|
-
self._check_route_conflicts(route, key)
|
|
168
|
+
self._check_route_conflicts(route, key, group)
|
|
169
169
|
# Path + methods so Get("/x") and Post("/x") can coexist
|
|
170
170
|
self.routes[key][f"{','.join(route.methods)} {route.path}"] = route_config
|
|
171
171
|
|
|
@@ -211,7 +211,7 @@ class Future:
|
|
|
211
211
|
route_group: RouteGroup,
|
|
212
212
|
parent_subdomain: str = "",
|
|
213
213
|
parent_prefix: str = "",
|
|
214
|
-
parent_middlewares: Optional[list[
|
|
214
|
+
parent_middlewares: Optional[list[IMiddleware]] = None,
|
|
215
215
|
nesting_depth: int = 0,
|
|
216
216
|
parent_group_names: Optional[list[str]] = None,
|
|
217
217
|
) -> None:
|
|
@@ -310,7 +310,7 @@ class Future:
|
|
|
310
310
|
|
|
311
311
|
return full_prefix
|
|
312
312
|
|
|
313
|
-
def _check_route_conflicts(self, route: Route, domain: str) -> None:
|
|
313
|
+
def _check_route_conflicts(self, route: Route, domain: str, group: Optional[dict[str, str]] = None) -> None:
|
|
314
314
|
"""Conflict only when the same path shares an HTTP method."""
|
|
315
315
|
existing_routes = self.routes.get(domain, {})
|
|
316
316
|
for existing in existing_routes.values():
|
|
@@ -318,8 +318,14 @@ class Future:
|
|
|
318
318
|
if other is None or getattr(other, "path", None) != route.path:
|
|
319
319
|
continue
|
|
320
320
|
overlap = set(other.methods) & set(route.methods)
|
|
321
|
-
if overlap:
|
|
322
|
-
|
|
321
|
+
if not overlap:
|
|
322
|
+
continue
|
|
323
|
+
methods = ",".join(sorted(overlap))
|
|
324
|
+
incoming_sub = (group or {}).get("subdomain") or ""
|
|
325
|
+
existing_sub = (existing.get("group") or {}).get("subdomain") or ""
|
|
326
|
+
if getattr(self, "domainless_mode", False) and incoming_sub != existing_sub and (incoming_sub or existing_sub):
|
|
327
|
+
raise ValueError(f"Route conflict detected: {methods} {route.path} already exists. In domainless mode (APP_DOMAIN is empty), RouteGroup subdomains are ignored, so {existing_sub!r} and {incoming_sub!r} both register {route.path}. Set APP_DOMAIN to enable subdomain routing, or use different prefixes.")
|
|
328
|
+
raise ValueError(f"Route conflict detected: {methods} {route.path} already exists in domain {domain}")
|
|
323
329
|
|
|
324
330
|
def _validate_domain_access(self, host_domain: str) -> bool:
|
|
325
331
|
"""Validate if the host domain is allowed to access routes."""
|
{future_framework-1.1.2 → future_framework-2.0.0}/future/authentication/BasicAuthentication.py
RENAMED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Regular username & password authentication (check against SQL database, generating a JWT).
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from future.
|
|
5
|
+
from future.interfaces.IAuthentication import IAuthentication
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class BasicAuthentication(
|
|
8
|
+
class BasicAuthentication(IAuthentication):
|
|
9
9
|
auth_type = "basic"
|
|
File without changes
|