django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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.
Files changed (225) hide show
  1. django_cfg/apps/agents/management/commands/create_agent.py +1 -1
  2. django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
  3. django_cfg/apps/newsletter/serializers.py +40 -3
  4. django_cfg/apps/newsletter/views/campaigns.py +12 -3
  5. django_cfg/apps/newsletter/views/emails.py +14 -3
  6. django_cfg/apps/newsletter/views/subscriptions.py +12 -2
  7. django_cfg/apps/payments/views/api/currencies.py +49 -6
  8. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  9. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  10. django_cfg/apps/payments/views/overview/views.py +2 -1
  11. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  12. django_cfg/apps/urls.py +106 -45
  13. django_cfg/core/base/config_model.py +2 -2
  14. django_cfg/core/constants.py +1 -1
  15. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  16. django_cfg/core/generation/integration_generators/api.py +73 -49
  17. django_cfg/core/integration/display/startup.py +30 -22
  18. django_cfg/core/integration/url_integration.py +15 -16
  19. django_cfg/management/commands/check_endpoints.py +11 -160
  20. django_cfg/management/commands/check_settings.py +13 -348
  21. django_cfg/management/commands/clear_constance.py +13 -201
  22. django_cfg/management/commands/create_token.py +13 -321
  23. django_cfg/management/commands/generate_clients.py +23 -0
  24. django_cfg/management/commands/list_urls.py +13 -306
  25. django_cfg/management/commands/migrate_all.py +13 -126
  26. django_cfg/management/commands/migrator.py +13 -396
  27. django_cfg/management/commands/rundramatiq.py +15 -247
  28. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  29. django_cfg/management/commands/runserver_ngrok.py +15 -160
  30. django_cfg/management/commands/script.py +12 -488
  31. django_cfg/management/commands/show_config.py +12 -215
  32. django_cfg/management/commands/show_urls.py +12 -342
  33. django_cfg/management/commands/superuser.py +15 -295
  34. django_cfg/management/commands/task_clear.py +14 -217
  35. django_cfg/management/commands/task_status.py +13 -248
  36. django_cfg/management/commands/test_email.py +15 -86
  37. django_cfg/management/commands/test_telegram.py +14 -61
  38. django_cfg/management/commands/test_twilio.py +15 -105
  39. django_cfg/management/commands/tree.py +13 -383
  40. django_cfg/management/commands/validate_openapi.py +10 -0
  41. django_cfg/middleware/README.md +1 -1
  42. django_cfg/middleware/user_activity.py +3 -3
  43. django_cfg/models/__init__.py +2 -2
  44. django_cfg/models/api/drf/spectacular.py +6 -6
  45. django_cfg/models/django/__init__.py +2 -2
  46. django_cfg/models/django/openapi.py +162 -0
  47. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  48. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  49. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  50. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  51. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  52. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  53. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  54. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  55. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  56. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  57. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  58. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  59. django_cfg/modules/django_client/__init__.py +20 -0
  60. django_cfg/modules/django_client/apps.py +35 -0
  61. django_cfg/modules/django_client/core/__init__.py +56 -0
  62. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  63. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  64. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  65. django_cfg/modules/django_client/core/cli/main.py +235 -0
  66. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  67. django_cfg/modules/django_client/core/config/config.py +208 -0
  68. django_cfg/modules/django_client/core/config/group.py +101 -0
  69. django_cfg/modules/django_client/core/config/service.py +209 -0
  70. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  71. django_cfg/modules/django_client/core/generator/base.py +838 -0
  72. django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
  73. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
  74. django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
  75. django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
  76. django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
  77. django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
  78. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
  79. django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
  80. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
  81. django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
  82. django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
  83. django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
  84. django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
  85. django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
  86. django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
  87. django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
  88. django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
  89. django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
  90. django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
  91. django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
  92. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
  93. django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
  94. django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
  95. django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
  96. django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
  97. django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
  98. django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
  99. django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
  100. django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
  101. django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
  102. django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
  103. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
  104. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
  105. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
  106. django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
  107. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
  108. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
  109. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
  110. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
  111. django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
  112. django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
  113. django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
  114. django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
  115. django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
  116. django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
  117. django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
  118. django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
  119. django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
  120. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
  121. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
  122. django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
  123. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
  124. django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
  125. django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
  126. django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
  127. django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
  128. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
  129. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
  130. django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
  131. django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
  132. django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
  133. django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
  134. django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
  135. django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
  136. django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
  137. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  138. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  139. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  140. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  141. django_cfg/modules/django_client/core/ir/context.py +387 -0
  142. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  143. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  144. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  145. django_cfg/modules/django_client/core/parser/base.py +648 -0
  146. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  147. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  148. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  149. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  150. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  151. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  152. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  153. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  154. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  155. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  156. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  157. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  158. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  159. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  160. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  161. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  162. django_cfg/modules/django_client/management/__init__.py +3 -0
  163. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  164. django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
  165. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  166. django_cfg/modules/django_client/pytest.ini +30 -0
  167. django_cfg/modules/django_client/spectacular/__init__.py +10 -0
  168. django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
  169. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  170. django_cfg/modules/django_client/urls.py +72 -0
  171. django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
  172. django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
  173. django_cfg/modules/django_dashboard/management/__init__.py +0 -0
  174. django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
  175. django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
  176. django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
  177. django_cfg/modules/django_email/management/__init__.py +0 -0
  178. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  179. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  180. django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
  181. django_cfg/modules/django_logging/django_logger.py +6 -6
  182. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  183. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  184. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  185. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  186. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  187. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  188. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  189. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  190. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  191. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  192. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  193. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  194. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  195. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  196. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  197. django_cfg/modules/django_unfold/callbacks/main.py +21 -10
  198. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  199. django_cfg/pyproject.toml +2 -6
  200. django_cfg/registry/third_party.py +5 -7
  201. django_cfg/routing/callbacks.py +1 -1
  202. django_cfg/static/admin/css/prose-unfold.css +666 -0
  203. django_cfg/templates/admin/index.html +8 -0
  204. django_cfg/templates/admin/index_new.html +13 -0
  205. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  206. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  207. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  208. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
  209. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
  210. django_cfg/management/commands/generate.py +0 -107
  211. /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
  212. /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
  213. /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
  214. /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
  215. /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
  216. /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
  217. /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
  218. /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
  219. /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
  220. /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
  221. /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
  222. /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
  223. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
  224. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
  225. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,9 @@
1
+ from .client import APIClient
2
+ from .models import *
3
+ {% if has_enums %}
4
+ from .enums import *
5
+ {% endif %}
6
+
7
+ __all__ = [
8
+ "APIClient",
9
+ ]
@@ -0,0 +1,153 @@
1
+ class API:
2
+ """
3
+ API Client wrapper with JWT token management.
4
+
5
+ This class provides:
6
+ - Thread-safe JWT token storage
7
+ - Automatic Authorization header injection
8
+ - Context manager support for async operations
9
+ - Optional retry and logging configuration
10
+
11
+ Example:
12
+ >>> api = API('https://api.example.com')
13
+ >>> api.set_token('jwt-token')
14
+ >>> async with api:
15
+ ... users = await api.users.list()
16
+ >>>
17
+ >>> # With retry and logging
18
+ >>> api = API(
19
+ ... 'https://api.example.com',
20
+ ... retry_config=RetryConfig(max_attempts=5),
21
+ ... logger_config=LoggerConfig(enabled=True)
22
+ ... )
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ base_url: str,
28
+ logger_config: LoggerConfig | None = None,
29
+ retry_config: RetryConfig | None = None,
30
+ **kwargs: Any
31
+ ):
32
+ """
33
+ Initialize API client.
34
+
35
+ Args:
36
+ base_url: Base API URL (e.g., 'https://api.example.com')
37
+ logger_config: Logger configuration (None to disable logging)
38
+ retry_config: Retry configuration (None to disable retry)
39
+ **kwargs: Additional httpx.AsyncClient kwargs
40
+ """
41
+ self.base_url = base_url.rstrip('/')
42
+ self._kwargs = kwargs
43
+ self._logger_config = logger_config
44
+ self._retry_config = retry_config
45
+ self._token: str | None = None
46
+ self._refresh_token: str | None = None
47
+ self._lock = threading.Lock()
48
+ self._client: APIClient | None = None
49
+ self._init_clients()
50
+
51
+ def _init_clients(self) -> None:
52
+ """Initialize API client with current token."""
53
+ # Create httpx client with auth header if token exists
54
+ headers = {}
55
+ if self._token:
56
+ headers['Authorization'] = f'Bearer {self._token}'
57
+
58
+ kwargs = {**self._kwargs}
59
+ if headers:
60
+ kwargs['headers'] = headers
61
+
62
+ # Create new APIClient
63
+ self._client = APIClient(
64
+ self.base_url,
65
+ logger_config=self._logger_config,
66
+ retry_config=self._retry_config,
67
+ **kwargs
68
+ )
69
+
70
+ {% for prop in properties %}
71
+ @property
72
+ def {{ prop.property }}(self) -> {{ prop.class_name }}:
73
+ """Access {{ prop.tag }} endpoints."""
74
+ return self._client.{{ prop.property }}
75
+
76
+ {% endfor %}
77
+ def get_token(self) -> str | None:
78
+ """Get current JWT token."""
79
+ with self._lock:
80
+ return self._token
81
+
82
+ def get_refresh_token(self) -> str | None:
83
+ """Get current refresh token."""
84
+ with self._lock:
85
+ return self._refresh_token
86
+
87
+ def set_token(self, token: str, refresh_token: str | None = None) -> None:
88
+ """
89
+ Set JWT token and refresh token.
90
+
91
+ Args:
92
+ token: JWT access token
93
+ refresh_token: JWT refresh token (optional)
94
+ """
95
+ with self._lock:
96
+ self._token = token
97
+ if refresh_token:
98
+ self._refresh_token = refresh_token
99
+
100
+ # Reinitialize clients with new token
101
+ self._init_clients()
102
+
103
+ def clear_tokens(self) -> None:
104
+ """Clear all tokens."""
105
+ with self._lock:
106
+ self._token = None
107
+ self._refresh_token = None
108
+
109
+ # Reinitialize clients without token
110
+ self._init_clients()
111
+
112
+ def is_authenticated(self) -> bool:
113
+ """Check if user is authenticated."""
114
+ return self.get_token() is not None
115
+
116
+ def set_base_url(self, url: str) -> None:
117
+ """
118
+ Update base URL and reinitialize clients.
119
+
120
+ Args:
121
+ url: New base URL
122
+ """
123
+ self.base_url = url.rstrip('/')
124
+ self._init_clients()
125
+
126
+ def get_base_url(self) -> str:
127
+ """Get current base URL."""
128
+ return self.base_url
129
+
130
+ def get_schema(self) -> dict[str, Any]:
131
+ """
132
+ Get OpenAPI schema.
133
+
134
+ Returns:
135
+ Complete OpenAPI specification for this API
136
+ """
137
+ return OPENAPI_SCHEMA
138
+
139
+ async def __aenter__(self) -> 'API':
140
+ """Async context manager entry."""
141
+ if self._client:
142
+ await self._client.__aenter__()
143
+ return self
144
+
145
+ async def __aexit__(self, *args: Any) -> None:
146
+ """Async context manager exit."""
147
+ if self._client:
148
+ await self._client.__aexit__(*args)
149
+
150
+ async def close(self) -> None:
151
+ """Close HTTP client."""
152
+ if self._client:
153
+ await self._client.close()
@@ -0,0 +1,6 @@
1
+ from .client import {{ class_name }}
2
+ from .models import *
3
+
4
+ __all__ = [
5
+ "{{ class_name }}",
6
+ ]
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from .models import *
6
+
7
+
8
+ class {{ class_name }}:
9
+ """API endpoints for {{ tag }}."""
10
+
11
+ def __init__(self, client: httpx.AsyncClient):
12
+ """Initialize sub-client with shared httpx client."""
13
+ self._client = client
14
+
15
+ {% for operation in operations %}
16
+ {{ operation | indent(4, first=True) }}
17
+
18
+ {% endfor %}
@@ -0,0 +1,38 @@
1
+ class APIClient:
2
+ """
3
+ Async API client for {{ api_title }}.
4
+
5
+ Usage:
6
+ >>> async with APIClient(base_url='https://api.example.com') as client:
7
+ ... users = await client.users_list()
8
+ """
9
+
10
+ def __init__(self, base_url: str, **kwargs: Any):
11
+ """
12
+ Initialize API client.
13
+
14
+ Args:
15
+ base_url: Base API URL (e.g., 'https://api.example.com')
16
+ **kwargs: Additional httpx.AsyncClient kwargs
17
+ """
18
+ self.base_url = base_url.rstrip('/')
19
+ self._client = httpx.AsyncClient(
20
+ base_url=self.base_url,
21
+ timeout=30.0,
22
+ **kwargs,
23
+ )
24
+
25
+ async def __aenter__(self) -> 'APIClient':
26
+ return self
27
+
28
+ async def __aexit__(self, *args: Any) -> None:
29
+ await self._client.aclose()
30
+
31
+ async def close(self) -> None:
32
+ """Close HTTP client."""
33
+ await self._client.aclose()
34
+
35
+ {% for operation in operations %}
36
+ {{ operation }}
37
+
38
+ {% endfor %}
@@ -0,0 +1,68 @@
1
+ class APIClient:
2
+ """
3
+ Async API client for {{ api_title }}.
4
+
5
+ Usage:
6
+ >>> async with APIClient(base_url='https://api.example.com') as client:
7
+ ... users = await client.users.list()
8
+ ... post = await client.posts.create(data=new_post)
9
+ >>>
10
+ >>> # With retry configuration
11
+ >>> retry_config = RetryConfig(max_attempts=5, min_wait=2.0)
12
+ >>> async with APIClient(base_url='https://api.example.com', retry_config=retry_config) as client:
13
+ ... users = await client.users.list()
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ base_url: str,
19
+ logger_config: Optional[LoggerConfig] = None,
20
+ retry_config: Optional[RetryConfig] = None,
21
+ **kwargs: Any,
22
+ ):
23
+ """
24
+ Initialize API client.
25
+
26
+ Args:
27
+ base_url: Base API URL (e.g., 'https://api.example.com')
28
+ logger_config: Logger configuration (None to disable logging)
29
+ retry_config: Retry configuration (None to disable retry)
30
+ **kwargs: Additional httpx.AsyncClient kwargs
31
+ """
32
+ self.base_url = base_url.rstrip('/')
33
+
34
+ # Create HTTP client with or without retry
35
+ if retry_config is not None:
36
+ self._client = RetryAsyncClient(
37
+ base_url=self.base_url,
38
+ retry_config=retry_config,
39
+ timeout=30.0,
40
+ **kwargs,
41
+ )
42
+ else:
43
+ self._client = httpx.AsyncClient(
44
+ base_url=self.base_url,
45
+ timeout=30.0,
46
+ **kwargs,
47
+ )
48
+
49
+ # Initialize logger
50
+ self.logger: Optional[APILogger] = None
51
+ if logger_config is not None:
52
+ self.logger = APILogger(logger_config)
53
+
54
+ # Initialize sub-clients
55
+ {% for tag in tags %}
56
+ self.{{ tag.property }} = {{ tag.class_name }}(self._client)
57
+ {% endfor %}
58
+
59
+ async def __aenter__(self) -> 'APIClient':
60
+ await self._client.__aenter__()
61
+ return self
62
+
63
+ async def __aexit__(self, *args: Any) -> None:
64
+ await self._client.__aexit__(*args)
65
+
66
+ async def close(self) -> None:
67
+ """Close HTTP client."""
68
+ await self._client.aclose()
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Optional
4
+
5
+ import httpx
6
+
7
+ {% for tag in tags %}
8
+ from .{{ tag.slug }} import {{ tag.class_name }}
9
+ {% endfor %}
10
+ from .logger import APILogger, LoggerConfig
11
+ from .retry import RetryConfig, RetryAsyncClient
12
+
13
+
14
+ {{ client_code }}
@@ -0,0 +1,9 @@
1
+ async def {{ method_name }}({{ params | join(', ') }}) -> {{ return_type }}:
2
+ {% if docstring %}
3
+ """
4
+ {{ docstring | indent(4, first=True) }}
5
+ """
6
+ {% endif %}
7
+ {% for line in body_lines %}
8
+ {{ line }}
9
+ {% endfor %}
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from .models import *
6
+
7
+
8
+ class {{ class_name }}:
9
+ """API endpoints for {{ tag }}."""
10
+
11
+ def __init__(self, client: httpx.AsyncClient):
12
+ """Initialize sub-client with shared httpx client."""
13
+ self._client = client
14
+
15
+ {% for operation in operations %}
16
+ {{ operation | indent(4, first=True) }}
17
+
18
+ {% endfor %}
@@ -0,0 +1,50 @@
1
+ class SyncAPIClient:
2
+ """
3
+ Synchronous API client for {{ api_title }}.
4
+
5
+ Usage:
6
+ >>> with SyncAPIClient(base_url='https://api.example.com') as client:
7
+ ... users = client.users.list()
8
+ ... post = client.posts.create(data=new_post)
9
+ """
10
+
11
+ def __init__(
12
+ self,
13
+ base_url: str,
14
+ logger_config: Optional[LoggerConfig] = None,
15
+ **kwargs: Any,
16
+ ):
17
+ """
18
+ Initialize sync API client.
19
+
20
+ Args:
21
+ base_url: Base API URL (e.g., 'https://api.example.com')
22
+ logger_config: Logger configuration (None to disable logging)
23
+ **kwargs: Additional httpx.Client kwargs
24
+ """
25
+ self.base_url = base_url.rstrip('/')
26
+ self._client = httpx.Client(
27
+ base_url=self.base_url,
28
+ timeout=30.0,
29
+ **kwargs,
30
+ )
31
+
32
+ # Initialize logger
33
+ self.logger: Optional[APILogger] = None
34
+ if logger_config is not None:
35
+ self.logger = APILogger(logger_config)
36
+
37
+ # Initialize sub-clients
38
+ {% for tag in tags %}
39
+ self.{{ tag.property }} = Sync{{ tag.class_name }}(self._client)
40
+ {% endfor %}
41
+
42
+ def __enter__(self) -> 'SyncAPIClient':
43
+ return self
44
+
45
+ def __exit__(self, *args: Any) -> None:
46
+ self._client.close()
47
+
48
+ def close(self) -> None:
49
+ """Close HTTP client."""
50
+ self._client.close()
@@ -0,0 +1,9 @@
1
+ def {{ method_name }}({{ params | join(', ') }}) -> {{ return_type }}:
2
+ {% if docstring %}
3
+ """
4
+ {{ docstring | indent(4, first=True) }}
5
+ """
6
+ {% endif %}
7
+ {% for line in body_lines %}
8
+ {{ line }}
9
+ {% endfor %}
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from .models import *
6
+
7
+
8
+ class Sync{{ class_name }}:
9
+ """Synchronous API endpoints for {{ tag }}."""
10
+
11
+ def __init__(self, client: httpx.Client):
12
+ """Initialize sync sub-client with shared httpx client."""
13
+ self._client = client
14
+
15
+ {% for operation in operations %}
16
+ {{ operation | indent(4, first=True) }}
17
+
18
+ {% endfor %}
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from .models import *
8
+ {% if has_enums %}
9
+ from .enums import *
10
+ {% endif %}
11
+
12
+
13
+ {{ client_code }}
@@ -0,0 +1,52 @@
1
+ """
2
+ {{ api_title }} - API Client with JWT Management
3
+
4
+ Usage:
5
+ >>> from api import API
6
+ >>>
7
+ >>> api = API('https://api.example.com')
8
+ >>>
9
+ >>> # Set JWT token
10
+ >>> api.set_token('your-jwt-token', 'refresh-token')
11
+ >>>
12
+ >>> # Use API
13
+ >>> async with api:
14
+ ... posts = await api.posts.list()
15
+ ... user = await api.users.retrieve(1)
16
+ >>>
17
+ >>> # Check authentication
18
+ >>> if api.is_authenticated():
19
+ ... # ...
20
+ >>>
21
+ >>> # Get OpenAPI schema
22
+ >>> schema = api.get_schema()
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import threading
28
+ from typing import Any
29
+
30
+ import httpx
31
+
32
+ from .client import APIClient
33
+ from .schema import OPENAPI_SCHEMA
34
+ from .logger import LoggerConfig
35
+ from .retry import RetryConfig
36
+ {% for tag in tags %}
37
+ from .{{ tag.slug }} import {{ tag.class_name }}
38
+ {% endfor %}
39
+ {% if has_enums %}
40
+ from . import enums
41
+ from .enums import {{ enum_names | join(', ') }}
42
+ {% endif %}
43
+
44
+ TOKEN_KEY = "auth_token"
45
+ REFRESH_TOKEN_KEY = "refresh_token"
46
+
47
+ {{ api_class }}
48
+
49
+ __all__ = [
50
+ "API",
51
+ "APIClient",
52
+ ]
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+ {% if has_enums and enum_names %}
8
+
9
+ from ..enums import {{ enum_names | join(', ') }}
10
+ {% endif %}
11
+
12
+
13
+ {% for schema in schemas %}
14
+ {{ schema }}
15
+
16
+
17
+ {% endfor %}
@@ -0,0 +1,17 @@
1
+ class {{ name }}({{ base_class }}):
2
+ {% if docstring %}
3
+ """
4
+ {{ docstring | indent(4, first=True) }}
5
+ """
6
+ {% endif %}
7
+ {% if members %}
8
+ {% if docstring %}
9
+
10
+ {% endif %}
11
+ {% for member in members %}
12
+ {{ member }}
13
+ {% endfor %}
14
+ {% else %}
15
+
16
+ pass
17
+ {% endif %}
@@ -0,0 +1,8 @@
1
+ from enum import IntEnum, StrEnum
2
+
3
+
4
+ {% for enum in enums %}
5
+ {{ enum }}
6
+
7
+
8
+ {% endfor %}
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+ {% if has_enums %}
8
+
9
+ from .enums import *
10
+ {% endif %}
11
+
12
+
13
+ {% for schema in schemas %}
14
+ {{ schema }}
15
+
16
+
17
+ {% endfor %}
@@ -0,0 +1,21 @@
1
+ class {{ name }}(BaseModel):
2
+ {% if docstring %}
3
+ """
4
+ {{ docstring | indent(4, first=True) }}
5
+ """
6
+ {% endif %}
7
+
8
+ model_config = ConfigDict(
9
+ validate_assignment=True,
10
+ extra="forbid",
11
+ frozen=False,
12
+ )
13
+ {% if fields %}
14
+
15
+ {% for field in fields %}
16
+ {{ field }}
17
+ {% endfor %}
18
+ {% else %}
19
+
20
+ pass
21
+ {% endif %}
@@ -0,0 +1,55 @@
1
+ [tool.poetry]
2
+ name = "{{ package_name }}"
3
+ version = "{{ version }}"
4
+ description = "{{ description }}"
5
+ authors = {{ authors | tojson }}
6
+ license = "{{ license }}"
7
+ readme = "README.md"
8
+ {% if repository_url %}repository = "{{ repository_url }}"
9
+ {% endif %}keywords = {{ keywords | tojson }}
10
+ classifiers = [
11
+ "Development Status :: 5 - Production/Stable",
12
+ "Intended Audience :: Developers",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Typing :: Typed",
17
+ ]
18
+
19
+ [tool.poetry.dependencies]
20
+ python = "{{ python_version }}"
21
+ pydantic = "^2.12"
22
+ httpx = "^0.28"
23
+ tenacity = "^9.1"
24
+ rich = "^14.1.0"
25
+
26
+ [tool.poetry.group.dev.dependencies]
27
+ pytest = "^8.0"
28
+ pytest-asyncio = "^0.24"
29
+ pytest-cov = "^6.0"
30
+ mypy = "^1.18"
31
+ ruff = "^0.13"
32
+
33
+ [build-system]
34
+ requires = ["poetry-core"]
35
+ build-backend = "poetry.core.masonry.api"
36
+
37
+ [tool.mypy]
38
+ python_version = "3.12"
39
+ strict = true
40
+ warn_return_any = true
41
+ warn_unused_configs = true
42
+ disallow_untyped_defs = true
43
+
44
+ [tool.ruff]
45
+ line-length = 100
46
+ target-version = "py312"
47
+
48
+ [tool.ruff.lint]
49
+ select = ["E", "F", "I", "N", "UP", "B"]
50
+ ignore = []
51
+
52
+ [tool.pytest.ini_options]
53
+ asyncio_mode = "auto"
54
+ testpaths = ["tests"]
55
+ addopts = "--cov={{ package_name | replace('-', '_') }} --cov-report=html --cov-report=term"