django-cfg 1.4.25__py3-none-any.whl → 1.4.26__py3-none-any.whl
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.
- django_cfg/apps/ipc/services/client/config.py +7 -0
- django_cfg/apps/urls.py +36 -2
- django_cfg/models/infrastructure/cache.py +5 -1
- django_cfg/models/infrastructure/database/validators.py +5 -1
- django_cfg/models/services/telegram.py +5 -1
- django_cfg/modules/django_logging/__init__.py +8 -1
- django_cfg/modules/django_logging/django_logger.py +44 -2
- django_cfg/pyproject.toml +1 -1
- {django_cfg-1.4.25.dist-info → django_cfg-1.4.26.dist-info}/METADATA +1 -1
- {django_cfg-1.4.25.dist-info → django_cfg-1.4.26.dist-info}/RECORD +13 -13
- {django_cfg-1.4.25.dist-info → django_cfg-1.4.26.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.25.dist-info → django_cfg-1.4.26.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.25.dist-info → django_cfg-1.4.26.dist-info}/licenses/LICENSE +0 -0
@@ -131,6 +131,8 @@ class DjangoCfgRPCConfig(BaseModel):
|
|
131
131
|
"""
|
132
132
|
Validate Redis URL format.
|
133
133
|
|
134
|
+
Allows environment variable templates like ${VAR:-default}.
|
135
|
+
|
134
136
|
Args:
|
135
137
|
v: Redis URL to validate
|
136
138
|
|
@@ -140,6 +142,11 @@ class DjangoCfgRPCConfig(BaseModel):
|
|
140
142
|
Raises:
|
141
143
|
ValueError: If URL format is invalid
|
142
144
|
"""
|
145
|
+
# Skip validation for environment variable templates
|
146
|
+
if v.startswith("${") and "}" in v:
|
147
|
+
return v
|
148
|
+
|
149
|
+
# Validate actual URLs
|
143
150
|
if not v.startswith("redis://") and not v.startswith("rediss://"):
|
144
151
|
raise ValueError(
|
145
152
|
"redis_url must start with 'redis://' or 'rediss://' "
|
django_cfg/apps/urls.py
CHANGED
@@ -4,10 +4,15 @@ Django CFG API URLs
|
|
4
4
|
Built-in API endpoints for django_cfg functionality.
|
5
5
|
"""
|
6
6
|
|
7
|
+
import traceback
|
7
8
|
from typing import List
|
8
9
|
|
9
10
|
from django.urls import include, path
|
10
11
|
|
12
|
+
from django_cfg.modules.django_logging import get_logger, sanitize_extra
|
13
|
+
|
14
|
+
logger = get_logger(__name__)
|
15
|
+
|
11
16
|
|
12
17
|
def get_enabled_cfg_apps() -> List[str]:
|
13
18
|
"""
|
@@ -85,10 +90,39 @@ def get_default_cfg_group():
|
|
85
90
|
|
86
91
|
|
87
92
|
def _safe_include(pattern_path: str, module_path: str):
|
88
|
-
"""
|
93
|
+
"""
|
94
|
+
Helper to safely include URL module if it exists.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
pattern_path: URL pattern (e.g., 'cfg/knowbase/')
|
98
|
+
module_path: Module path (e.g., 'django_cfg.apps.knowbase.urls')
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
URLPattern if successful, None if import fails
|
102
|
+
"""
|
89
103
|
try:
|
90
104
|
return path(pattern_path, include(module_path))
|
91
|
-
except ImportError:
|
105
|
+
except ImportError as e:
|
106
|
+
logger.warning(
|
107
|
+
f"Failed to import URL module '{module_path}' for pattern '{pattern_path}': {e}",
|
108
|
+
extra=sanitize_extra({
|
109
|
+
'pattern': pattern_path,
|
110
|
+
'module': module_path,
|
111
|
+
'error': str(e),
|
112
|
+
})
|
113
|
+
)
|
114
|
+
logger.debug(f"Traceback for '{module_path}':\n{traceback.format_exc()}")
|
115
|
+
return None
|
116
|
+
except Exception as e:
|
117
|
+
logger.error(
|
118
|
+
f"Unexpected error including URL module '{module_path}' for pattern '{pattern_path}': {e}",
|
119
|
+
extra=sanitize_extra({
|
120
|
+
'pattern': pattern_path,
|
121
|
+
'module': module_path,
|
122
|
+
'error': str(e),
|
123
|
+
'traceback': traceback.format_exc(),
|
124
|
+
})
|
125
|
+
)
|
92
126
|
return None
|
93
127
|
|
94
128
|
|
@@ -93,10 +93,14 @@ class CacheConfig(BaseModel):
|
|
93
93
|
@field_validator('redis_url')
|
94
94
|
@classmethod
|
95
95
|
def validate_redis_url(cls, v: Optional[str]) -> Optional[str]:
|
96
|
-
"""Validate Redis URL format."""
|
96
|
+
"""Validate Redis URL format. Allows environment variable templates like ${VAR:-default}."""
|
97
97
|
if v is None:
|
98
98
|
return v
|
99
99
|
|
100
|
+
# Skip validation for environment variable templates
|
101
|
+
if v.startswith("${") and "}" in v:
|
102
|
+
return v
|
103
|
+
|
100
104
|
if not v.startswith(('redis://', 'rediss://')):
|
101
105
|
raise ValueError(
|
102
106
|
"Redis URL must start with 'redis://' or 'rediss://' "
|
@@ -49,7 +49,11 @@ def validate_engine(v: Optional[str]) -> Optional[str]:
|
|
49
49
|
|
50
50
|
|
51
51
|
def validate_name(v: str) -> str:
|
52
|
-
"""Validate database name or parse connection string."""
|
52
|
+
"""Validate database name or parse connection string. Allows environment variable templates like ${VAR:-default}."""
|
53
|
+
# Skip validation for environment variable templates
|
54
|
+
if v.startswith("${") and "}" in v:
|
55
|
+
return v
|
56
|
+
|
53
57
|
# Check if it's a connection string
|
54
58
|
if "://" in v:
|
55
59
|
try:
|
@@ -124,10 +124,14 @@ class TelegramConfig(BaseModel):
|
|
124
124
|
@field_validator('webhook_url')
|
125
125
|
@classmethod
|
126
126
|
def validate_webhook_url(cls, v: Optional[str]) -> Optional[str]:
|
127
|
-
"""Validate webhook URL format."""
|
127
|
+
"""Validate webhook URL format. Allows environment variable templates like ${VAR:-default}."""
|
128
128
|
if v is None:
|
129
129
|
return v
|
130
130
|
|
131
|
+
# Skip validation for environment variable templates
|
132
|
+
if v.startswith("${") and "}" in v:
|
133
|
+
return v
|
134
|
+
|
131
135
|
if not v.startswith('https://'):
|
132
136
|
raise ValueError("Webhook URL must use HTTPS")
|
133
137
|
|
@@ -4,11 +4,18 @@ Django Logging Modules for django_cfg.
|
|
4
4
|
Auto-configuring logging utilities.
|
5
5
|
"""
|
6
6
|
|
7
|
-
from .django_logger import
|
7
|
+
from .django_logger import (
|
8
|
+
RESERVED_LOG_ATTRS,
|
9
|
+
DjangoLogger,
|
10
|
+
get_logger,
|
11
|
+
sanitize_extra,
|
12
|
+
)
|
8
13
|
from .logger import logger
|
9
14
|
|
10
15
|
__all__ = [
|
11
16
|
"logger",
|
12
17
|
"DjangoLogger",
|
13
18
|
"get_logger",
|
19
|
+
"sanitize_extra",
|
20
|
+
"RESERVED_LOG_ATTRS",
|
14
21
|
]
|
@@ -6,11 +6,53 @@ KISS principle: simple, unified logging configuration.
|
|
6
6
|
|
7
7
|
import logging
|
8
8
|
from pathlib import Path
|
9
|
-
from typing import Dict
|
9
|
+
from typing import Any, Dict, Optional
|
10
10
|
|
11
11
|
from ..base import BaseCfgModule
|
12
12
|
|
13
13
|
|
14
|
+
# Reserved LogRecord attributes that cannot be used in 'extra'
|
15
|
+
# Source: https://docs.python.org/3/library/logging.html#logrecord-attributes
|
16
|
+
RESERVED_LOG_ATTRS = {
|
17
|
+
'name', 'msg', 'args', 'created', 'filename', 'funcName', 'levelname',
|
18
|
+
'levelno', 'lineno', 'module', 'msecs', 'message', 'pathname', 'process',
|
19
|
+
'processName', 'relativeCreated', 'thread', 'threadName', 'exc_info',
|
20
|
+
'exc_text', 'stack_info', 'asctime', 'taskName'
|
21
|
+
}
|
22
|
+
|
23
|
+
|
24
|
+
def sanitize_extra(extra: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
25
|
+
"""
|
26
|
+
Sanitize extra dict by prefixing reserved LogRecord attributes.
|
27
|
+
|
28
|
+
Python's logging module reserves certain attribute names in LogRecord.
|
29
|
+
Using these names in the 'extra' parameter causes a KeyError.
|
30
|
+
This function automatically prefixes conflicting keys with 'ctx_'.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
extra: Dictionary of extra logging context
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
Sanitized dictionary with no reserved attribute conflicts
|
37
|
+
|
38
|
+
Example:
|
39
|
+
>>> sanitize_extra({'module': 'myapp', 'user_id': 123})
|
40
|
+
{'ctx_module': 'myapp', 'user_id': 123}
|
41
|
+
"""
|
42
|
+
if not extra:
|
43
|
+
return {}
|
44
|
+
|
45
|
+
sanitized = {}
|
46
|
+
for key, value in extra.items():
|
47
|
+
if key in RESERVED_LOG_ATTRS:
|
48
|
+
# Prefix reserved attributes with 'ctx_'
|
49
|
+
sanitized[f'ctx_{key}'] = value
|
50
|
+
else:
|
51
|
+
sanitized[key] = value
|
52
|
+
|
53
|
+
return sanitized
|
54
|
+
|
55
|
+
|
14
56
|
class DjangoLogger(BaseCfgModule):
|
15
57
|
"""Simple auto-configuring logger."""
|
16
58
|
|
@@ -205,4 +247,4 @@ def get_logger(name: str = "django_cfg") -> logging.Logger:
|
|
205
247
|
|
206
248
|
|
207
249
|
# Export public API
|
208
|
-
__all__ = ['DjangoLogger', 'get_logger']
|
250
|
+
__all__ = ['DjangoLogger', 'get_logger', 'sanitize_extra', 'RESERVED_LOG_ATTRS']
|
django_cfg/pyproject.toml
CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "django-cfg"
|
7
|
-
version = "1.4.
|
7
|
+
version = "1.4.26"
|
8
8
|
description = "Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django."
|
9
9
|
readme = "README.md"
|
10
10
|
keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "ai-agents", "enterprise-django", "django-settings", "type-safe-config",]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: django-cfg
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.26
|
4
4
|
Summary: Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django.
|
5
5
|
Project-URL: Homepage, https://djangocfg.com
|
6
6
|
Project-URL: Documentation, https://djangocfg.com
|
@@ -3,7 +3,7 @@ django_cfg/__init__.py,sha256=gzibt9NN48r10Bwz4ajKNEpxa_BIuaC2z2vE103-TKg,1619
|
|
3
3
|
django_cfg/apps.py,sha256=72m3uuvyqGiLx6gOfE-BD3P61jddCCERuBOYpxTX518,1605
|
4
4
|
django_cfg/config.py,sha256=y4Z3rnYsHBE0TehpwAIPaxr---mkvyKrZGGsNwYso74,1398
|
5
5
|
django_cfg/apps/__init__.py,sha256=JtDmEYt1OcleWM2ZaeX0LKDnRQzPOavfaXBWG4ECB5Q,26
|
6
|
-
django_cfg/apps/urls.py,sha256=
|
6
|
+
django_cfg/apps/urls.py,sha256=ZCfTW14N4sVR6SUElheIuWN0UnLvQ-nJprBdMbmlNIM,6094
|
7
7
|
django_cfg/apps/accounts/README.md,sha256=YkUYJ3iKMYTmm9ALK2PDnX75SDqZxgnkzNLCD5efxRs,8227
|
8
8
|
django_cfg/apps/accounts/__init__.py,sha256=I9pq6H5oOFv59Du0VP-g7KsAUDhjKeUcP0spMvhtIjk,99
|
9
9
|
django_cfg/apps/accounts/__models.py,sha256=fYhobXbGIYKnG4mZ_pwNePei8O-SHHqgBMhe6qhH3KQ,10075
|
@@ -125,7 +125,7 @@ django_cfg/apps/ipc/services/__init__.py,sha256=YdHT1pd7FZbjYFaPAf3rw_t3NIHA-6TI
|
|
125
125
|
django_cfg/apps/ipc/services/monitor.py,sha256=NjZdNACiFggi9HgjXRwVDdj5DfloYeO5OuOe6XIAtZs,15368
|
126
126
|
django_cfg/apps/ipc/services/client/__init__.py,sha256=diiN9vU_Tpq8_zML3dMHldpqycsbCt51JKiQC6pJ0ZU,444
|
127
127
|
django_cfg/apps/ipc/services/client/client.py,sha256=aSCa_wjw0XPntd2KL2tQUsu3iOXdwT2KHOwFK9vb4xo,17479
|
128
|
-
django_cfg/apps/ipc/services/client/config.py,sha256=
|
128
|
+
django_cfg/apps/ipc/services/client/config.py,sha256=A6xWzRfVb03hatoHmT8saePy3zPHgm0FOwXKT8QShOY,5895
|
129
129
|
django_cfg/apps/ipc/services/client/exceptions.py,sha256=vAnZgH4ZYnqs7HJs11Rm6oqM-aTVAdPVcQZ9NcpE6Ik,5866
|
130
130
|
django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs,sha256=FTumHeB_IwfsQvgm5_teC8UAw-baTGIrrR1nXDSMocc,16187
|
131
131
|
django_cfg/apps/ipc/templates/django_cfg_ipc/base.html,sha256=naTYIAlETt00FVVBmz-dB5iPWekITagkTgGgKb25N60,2405
|
@@ -675,7 +675,7 @@ django_cfg/models/django/environment.py,sha256=lBCHBs1lphv9tlu1BCTfLZeH_kUame0p6
|
|
675
675
|
django_cfg/models/django/openapi.py,sha256=avE3iapaCj8eyOqVUum_v2EExR3V-hwHrexqtXMHtTQ,3739
|
676
676
|
django_cfg/models/django/revolution_legacy.py,sha256=Z4SPUS7QSv62EuPAeFFoXGEgqLmdXnVEr7Ofk1IDtVc,8918
|
677
677
|
django_cfg/models/infrastructure/__init__.py,sha256=VdOapoHa_yPtme8dLEJsmOlmT2klGs8G62W5CES8e2E,369
|
678
|
-
django_cfg/models/infrastructure/cache.py,sha256
|
678
|
+
django_cfg/models/infrastructure/cache.py,sha256=-eN2GjDJo-4Ta6b4hamG-AuBHNEKoYK_LqVOt_fJvZE,12012
|
679
679
|
django_cfg/models/infrastructure/logging.py,sha256=dbbDJ0hjJKigKKTmqKnh7hkLzmipm3_abp-whaK1lOY,10314
|
680
680
|
django_cfg/models/infrastructure/security.py,sha256=buBduEiZT2PfpjqxBna7jeXC8x_dJHKFhpYa9SzNHzw,6202
|
681
681
|
django_cfg/models/infrastructure/database/__init__.py,sha256=3BXDKeJwvjyFws4MAjox_PIp_g0N1YuXv6qNjRb7wqQ,500
|
@@ -683,7 +683,7 @@ django_cfg/models/infrastructure/database/config.py,sha256=GLGwUPmZ3s_wyjRJWOmV8
|
|
683
683
|
django_cfg/models/infrastructure/database/converters.py,sha256=xRqL5rOSqOGA06KK5Z6nbx6waUm9WMAtHM4mxgXSI-0,3083
|
684
684
|
django_cfg/models/infrastructure/database/parsers.py,sha256=8q1hq95SHKHxL2_AcHRc9HkSB_ide1zTjbDn_WDyQXk,2667
|
685
685
|
django_cfg/models/infrastructure/database/routing.py,sha256=Z22AeCjKJB-aV0Scq9u1RDTRspKEf4jmCKwzWLIqDOk,1999
|
686
|
-
django_cfg/models/infrastructure/database/validators.py,sha256=
|
686
|
+
django_cfg/models/infrastructure/database/validators.py,sha256=VA6Y-t7DdU7cWI42kXTxUKMhf1XwNJ6_NkxPWlXv-l8,5854
|
687
687
|
django_cfg/models/ngrok/__init__.py,sha256=O_fMQ9teQDluusZr2XcTUirSJReaI_zaXN_vU_aoR_k,163
|
688
688
|
django_cfg/models/ngrok/auth.py,sha256=Domjz612_9GQit5lf2v2GmcVLc4gBfyAyJxO8LaVXCg,920
|
689
689
|
django_cfg/models/ngrok/config.py,sha256=nzW0_4FjeBvWDxVZCVzkOuUSBftt-8bmyofbm7nMaHc,2421
|
@@ -697,7 +697,7 @@ django_cfg/models/payments/providers/nowpayments.py,sha256=ds0FruxRkH1Oi-0AYoYjO
|
|
697
697
|
django_cfg/models/services/__init__.py,sha256=K3mit3rKumqC4XiCUU0BziZC3143j1SM9j0lEAwhtRY,419
|
698
698
|
django_cfg/models/services/base.py,sha256=q_QggR8i_6qoiIvbAubddCklpfjVfeLP3Bv2bsdT4BQ,1607
|
699
699
|
django_cfg/models/services/email.py,sha256=LyBGG1OVM8RefwMEZDhYwADmnBexEcQWxzYwOeF0du8,4694
|
700
|
-
django_cfg/models/services/telegram.py,sha256=
|
700
|
+
django_cfg/models/services/telegram.py,sha256=wrMqOGZCp1KAxRmCn5oxMU0BMBgbzsQD6o0Fi_7kfIY,4810
|
701
701
|
django_cfg/models/tasks/__init__.py,sha256=6t33r91zv_nyve1NfZeEziF0_mwgfAFuJpsnm38Ps3k,1320
|
702
702
|
django_cfg/models/tasks/backends.py,sha256=mGB92TdD-zwrVckFRZ0EA0WWWLiR-gRM2fVv5rINOzM,6823
|
703
703
|
django_cfg/models/tasks/config.py,sha256=dqDoiqMWsSdKJrLAyGcKyzBukZdjhz7kR5_LKFZBiss,9305
|
@@ -957,8 +957,8 @@ django_cfg/modules/django_llm/translator/utils/prompt_builder.py,sha256=ZSOnm9_e
|
|
957
957
|
django_cfg/modules/django_llm/translator/utils/text_utils.py,sha256=_7Z4n1oi2_Zl3NU8kbRiLa2dCRViyzFG6-sUIcEmnmE,2925
|
958
958
|
django_cfg/modules/django_logging/FIXES_SUMMARY.md,sha256=O2Dvecw-9gEbQkZVq6HfMrC3lfqkRMfn5YaHAp_Ay1s,7741
|
959
959
|
django_cfg/modules/django_logging/LOGGING_GUIDE.md,sha256=WVXefLk7tSEud7wo6sN-lk07buwQpkFAa4hV7Y5WYSk,14402
|
960
|
-
django_cfg/modules/django_logging/__init__.py,sha256=
|
961
|
-
django_cfg/modules/django_logging/django_logger.py,sha256=
|
960
|
+
django_cfg/modules/django_logging/__init__.py,sha256=T-R62HonMGkyyuyWzWtS94R5vteJlPgfT7GUBGMFJzg,336
|
961
|
+
django_cfg/modules/django_logging/django_logger.py,sha256=naiuFtiFueZtHH211hXSFNkPqc5apNST9WXXJ7aF84g,9866
|
962
962
|
django_cfg/modules/django_logging/logger.py,sha256=_8v70X5imm1KLDjMsgID5tTtpG6eSh4ozFZfYnb0IU4,10915
|
963
963
|
django_cfg/modules/django_ngrok/__init__.py,sha256=CYHHSKRIHIP3E_NpUnFX-D2exWZK8o_6wfqh1T8ZIyo,792
|
964
964
|
django_cfg/modules/django_ngrok/service.py,sha256=Xkh9Gl6Rth32UcT0UYjD0ckROHFw6FJLKDtg3VzWLQY,9304
|
@@ -1129,9 +1129,9 @@ django_cfg/utils/version_check.py,sha256=WO51J2m2e-wVqWCRwbultEwu3q1lQasV67Mw2aa
|
|
1129
1129
|
django_cfg/CHANGELOG.md,sha256=jtT3EprqEJkqSUh7IraP73vQ8PmKUMdRtznQsEnqDZk,2052
|
1130
1130
|
django_cfg/CONTRIBUTING.md,sha256=DU2kyQ6PU0Z24ob7O_OqKWEYHcZmJDgzw-lQCmu6uBg,3041
|
1131
1131
|
django_cfg/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
1132
|
-
django_cfg/pyproject.toml,sha256=
|
1133
|
-
django_cfg-1.4.
|
1134
|
-
django_cfg-1.4.
|
1135
|
-
django_cfg-1.4.
|
1136
|
-
django_cfg-1.4.
|
1137
|
-
django_cfg-1.4.
|
1132
|
+
django_cfg/pyproject.toml,sha256=OWxt7DEhKm-uRtTJpClmBxxZJFcAmrZfzWj4VTvtOPY,8210
|
1133
|
+
django_cfg-1.4.26.dist-info/METADATA,sha256=POQ9QT88Nx-kOV53_fuQ4bWAXFAJEb13C0blL5NbMsQ,22533
|
1134
|
+
django_cfg-1.4.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
1135
|
+
django_cfg-1.4.26.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
|
1136
|
+
django_cfg-1.4.26.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
1137
|
+
django_cfg-1.4.26.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|