future-framework 3.1.1__tar.gz → 3.1.2__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.
Files changed (85) hide show
  1. {future_framework-3.1.1 → future_framework-3.1.2}/PKG-INFO +1 -1
  2. {future_framework-3.1.1 → future_framework-3.1.2}/future/logger.py +43 -26
  3. {future_framework-3.1.1 → future_framework-3.1.2}/pyproject.toml +1 -1
  4. {future_framework-3.1.1 → future_framework-3.1.2}/pyproject.toml.orig +1 -1
  5. {future_framework-3.1.1 → future_framework-3.1.2}/LICENSE +0 -0
  6. {future_framework-3.1.1 → future_framework-3.1.2}/README.md +0 -0
  7. {future_framework-3.1.1 → future_framework-3.1.2}/future/__init__.py +0 -0
  8. {future_framework-3.1.1 → future_framework-3.1.2}/future/application.py +0 -0
  9. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/Auth0Authentication.py +0 -0
  10. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/AzureADAuthentication.py +0 -0
  11. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/BasicAuthentication.py +0 -0
  12. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/KerberosAuthentication.py +0 -0
  13. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/KeycloakAuthentication.py +0 -0
  14. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/OAuth2Authentication.py +0 -0
  15. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/OpenIdConnectAuthentication.py +0 -0
  16. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/SAMLAuthentication.py +0 -0
  17. {future_framework-3.1.1 → future_framework-3.1.2}/future/authentication/__init__.py +0 -0
  18. {future_framework-3.1.1 → future_framework-3.1.2}/future/cli.py +0 -0
  19. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/DebugController.py +0 -0
  20. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/GraphQLController.py +0 -0
  21. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/OpenAPIController.py +0 -0
  22. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/WebSocketController.py +0 -0
  23. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/WelcomeController.py +0 -0
  24. {future_framework-3.1.1 → future_framework-3.1.2}/future/controllers/__init__.py +0 -0
  25. {future_framework-3.1.1 → future_framework-3.1.2}/future/database.py +0 -0
  26. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/ClickhouseDatabase.py +0 -0
  27. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/ElasticsearchDatabase.py +0 -0
  28. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/MongoDBDatabase.py +0 -0
  29. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/MySQLDatabase.py +0 -0
  30. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/PostgresDatabase.py +0 -0
  31. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/RedisDatabase.py +0 -0
  32. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/SQLiteDatabase.py +0 -0
  33. {future_framework-3.1.1 → future_framework-3.1.2}/future/databases/__init__.py +0 -0
  34. {future_framework-3.1.1 → future_framework-3.1.2}/future/exceptions.py +0 -0
  35. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IAuthentication.py +0 -0
  36. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IController.py +0 -0
  37. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IDatabase.py +0 -0
  38. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IMiddleware.py +0 -0
  39. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IModel.py +0 -0
  40. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/IPlugin.py +0 -0
  41. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/ITask.py +0 -0
  42. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfaces/__init__.py +0 -0
  43. {future_framework-3.1.1 → future_framework-3.1.2}/future/interfacing.py +0 -0
  44. {future_framework-3.1.1 → future_framework-3.1.2}/future/lifespan.py +0 -0
  45. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/BruteforcePreventionMiddleware.py +0 -0
  46. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/CORSMiddleware.py +0 -0
  47. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/CSRFMiddleware.py +0 -0
  48. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/GZipMiddleware.py +0 -0
  49. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/HTAccessConfuserMiddleware.py +0 -0
  50. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/HeaderConfuserMiddleware.py +0 -0
  51. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/RateLimitMiddleware.py +0 -0
  52. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/ResponseCodeConfuserMiddleware.py +0 -0
  53. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/SQLiConfuserMiddleware.py +0 -0
  54. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/ScopeValidationMiddleware.py +0 -0
  55. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/SessionMiddleware.py +0 -0
  56. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/TestMiddlewareRequest.py +0 -0
  57. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/TestMiddlewareResponse.py +0 -0
  58. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/WebServerConfuserMiddleware.py +0 -0
  59. {future_framework-3.1.1 → future_framework-3.1.2}/future/middleware/__init__.py +0 -0
  60. {future_framework-3.1.1 → future_framework-3.1.2}/future/migrations.py +0 -0
  61. {future_framework-3.1.1 → future_framework-3.1.2}/future/models/PostModel.py +0 -0
  62. {future_framework-3.1.1 → future_framework-3.1.2}/future/models/Query.py +0 -0
  63. {future_framework-3.1.1 → future_framework-3.1.2}/future/models/UserModel.py +0 -0
  64. {future_framework-3.1.1 → future_framework-3.1.2}/future/models/__init__.py +0 -0
  65. {future_framework-3.1.1 → future_framework-3.1.2}/future/openapi.py +0 -0
  66. {future_framework-3.1.1 → future_framework-3.1.2}/future/plugins/ElasticsearchPlugin.py +0 -0
  67. {future_framework-3.1.1 → future_framework-3.1.2}/future/plugins/__init__.py +0 -0
  68. {future_framework-3.1.1 → future_framework-3.1.2}/future/request.py +0 -0
  69. {future_framework-3.1.1 → future_framework-3.1.2}/future/response.py +0 -0
  70. {future_framework-3.1.1 → future_framework-3.1.2}/future/routing.py +0 -0
  71. {future_framework-3.1.1 → future_framework-3.1.2}/future/scheduling.py +0 -0
  72. {future_framework-3.1.1 → future_framework-3.1.2}/future/seeder.py +0 -0
  73. {future_framework-3.1.1 → future_framework-3.1.2}/future/settings.py +0 -0
  74. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckDNSTask.py +0 -0
  75. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckDiskUsageTask.py +0 -0
  76. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckHttpStatusTask.py +0 -0
  77. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckMemoryUsageTask.py +0 -0
  78. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckSSHBannerTask.py +0 -0
  79. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/CheckSystemUptimeTask.py +0 -0
  80. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/DailyBackupTask.py +0 -0
  81. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/SyncTaskExample.py +0 -0
  82. {future_framework-3.1.1 → future_framework-3.1.2}/future/tasks/__init__.py +0 -0
  83. {future_framework-3.1.1 → future_framework-3.1.2}/future/taskscheduler.py +0 -0
  84. {future_framework-3.1.1 → future_framework-3.1.2}/future/testclient.py +0 -0
  85. {future_framework-3.1.1 → future_framework-3.1.2}/future/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: future-framework
3
- Version: 3.1.1
3
+ Version: 3.1.2
4
4
  Summary: ASGI-based framework for web APIs
5
5
  Author: nicolaipre
6
6
  License-Expression: MIT
@@ -1,4 +1,5 @@
1
1
  import atexit
2
+ import http
2
3
  import logging
3
4
  import logging.config
4
5
  import logging.handlers
@@ -11,36 +12,41 @@ from uvicorn.logging import AccessFormatter, DefaultFormatter
11
12
  from future.settings import LOGGING_CONFIG
12
13
 
13
14
 
15
+ RESET = "\033[0m"
16
+ LEVEL_COLORS = {
17
+ logging.DEBUG: "\033[36m", # Cyan
18
+ logging.INFO: "\033[32m", # Green
19
+ logging.WARNING: "\033[38;5;208m", # Orange
20
+ logging.ERROR: "\033[31m", # Red
21
+ logging.CRITICAL: "\033[91m", # Bright red
22
+ }
23
+ HTTP_STATUS_COLORS = {
24
+ 1: "\033[96m", # Bright cyan
25
+ 2: "\033[97m", # Bright white
26
+ 3: "\033[92m", # Bright green
27
+ 4: "\033[91m", # Bright red
28
+ 5: "\033[94m", # Bright blue
29
+ }
30
+ DEFAULT_LOG_FORMAT = "%(asctime)s %(levelprefix)s %(message)s"
31
+ ACCESS_LOG_FORMAT = '%(asctime)s %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s'
32
+
33
+
34
+ def _colorize(value: str, color: str | None) -> str:
35
+ return f"{color}{value}{RESET}" if color else value
36
+
37
+
14
38
  class UtcTimestampFormatter:
15
39
  """Render log timestamps as unambiguous ISO 8601 UTC values."""
16
40
 
17
41
  def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str:
18
42
  return datetime.fromtimestamp(record.created, timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
19
43
 
44
+ def color_level_name(self, level_name: str, level_no: int) -> str:
45
+ return _colorize(level_name, LEVEL_COLORS.get(level_no))
20
46
 
21
- # ANSI color codes
22
- class ColoredFormatter(UtcTimestampFormatter, logging.Formatter):
23
- """Custom formatter with colors like uvicorn"""
24
47
 
25
- COLORS = {
26
- "DEBUG": "\033[36m", # Cyan
27
- "INFO": "\033[32m", # Green
28
- "WARNING": "\033[33m", # Yellow
29
- "ERROR": "\033[31m", # Red
30
- "CRITICAL": "\033[35m", # Magenta
31
- }
32
- RESET = "\033[0m"
33
-
34
- def format(self, record: logging.LogRecord) -> str:
35
- message = super().format(record)
36
- timestamp = self.formatTime(record)
37
- levelname = record.levelname
38
- if levelname in self.COLORS:
39
- # Calculate padding based on original levelname length BEFORE adding colors
40
- padding = " " * (9 - len(levelname)) # 9 is max level length (CRITICAL) + 1
41
- colored_levelname = f"{self.COLORS[levelname]}{levelname}{self.RESET}"
42
- return f"{timestamp} {colored_levelname}:{padding}{message}"
43
- return f"{timestamp} {levelname}: {message}"
48
+ class ColoredFormatter(UtcTimestampFormatter, DefaultFormatter):
49
+ """Shared timestamp and level formatter for Future and Uvicorn."""
44
50
 
45
51
 
46
52
  class UvicornDefaultFormatter(UtcTimestampFormatter, DefaultFormatter):
@@ -50,6 +56,16 @@ class UvicornDefaultFormatter(UtcTimestampFormatter, DefaultFormatter):
50
56
  class UvicornAccessFormatter(UtcTimestampFormatter, AccessFormatter):
51
57
  """Uvicorn access formatter using Future's UTC timestamp format."""
52
58
 
59
+ def get_status_code(self, status_code: int) -> str:
60
+ try:
61
+ status_phrase = http.HTTPStatus(status_code).phrase
62
+ except ValueError:
63
+ status_phrase = ""
64
+ status_and_phrase = f"{status_code} {status_phrase}"
65
+ if not self.use_colors:
66
+ return status_and_phrase
67
+ return _colorize(status_and_phrase, HTTP_STATUS_COLORS.get(status_code // 100))
68
+
53
69
 
54
70
  def create_uvicorn_logging_config() -> dict[str, Any]:
55
71
  """Return a fresh Uvicorn logging config for each server invocation."""
@@ -59,12 +75,13 @@ def create_uvicorn_logging_config() -> dict[str, Any]:
59
75
  "formatters": {
60
76
  "default": {
61
77
  "()": UvicornDefaultFormatter,
62
- "fmt": "%(asctime)s %(levelprefix)s %(message)s",
63
- "use_colors": None,
78
+ "fmt": DEFAULT_LOG_FORMAT,
79
+ "use_colors": True,
64
80
  },
65
81
  "access": {
66
82
  "()": UvicornAccessFormatter,
67
- "fmt": '%(asctime)s %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
83
+ "fmt": ACCESS_LOG_FORMAT,
84
+ "use_colors": True,
68
85
  },
69
86
  },
70
87
  "handlers": {
@@ -91,7 +108,7 @@ def create_uvicorn_logging_config() -> dict[str, Any]:
91
108
  logging.config.dictConfig(LOGGING_CONFIG)
92
109
 
93
110
  log = logging.getLogger("future")
94
- formatter = ColoredFormatter("%(message)s")
111
+ formatter = ColoredFormatter(DEFAULT_LOG_FORMAT, use_colors=True)
95
112
 
96
113
  # QueueHandler itself does not format; the listener's stdout handler does.
97
114
  # Handler level NOTSET so Future's log.setLevel(APP_DEBUG) alone controls filtering.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "future-framework"
3
- version = "3.1.1"
3
+ version = "3.1.2"
4
4
  description = "ASGI-based framework for web APIs"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "future-framework"
3
- version = "3.1.1"
3
+ version = "3.1.2"
4
4
  description = "ASGI-based framework for web APIs"
5
5
  authors = [{ name = "nicolaipre" }]
6
6
  license = "MIT"