botversion-sdk 1.0.6__tar.gz → 1.1.7__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.
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/PKG-INFO +1 -1
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk/__init__.py +106 -12
- botversion_sdk-1.1.7/botversion_sdk/cli/__init__.py +0 -0
- botversion_sdk-1.1.7/botversion_sdk/cli/detector.py +1157 -0
- botversion_sdk-1.1.7/botversion_sdk/cli/generator.py +169 -0
- botversion_sdk-1.1.7/botversion_sdk/cli/init.py +673 -0
- botversion_sdk-1.1.7/botversion_sdk/cli/prompts.py +155 -0
- botversion_sdk-1.1.7/botversion_sdk/cli/writer.py +724 -0
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk/client.py +16 -8
- botversion_sdk-1.1.7/botversion_sdk/interceptor.py +679 -0
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk/scanner.py +659 -32
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk.egg-info/PKG-INFO +1 -1
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk.egg-info/SOURCES.txt +7 -2
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/pyproject.toml +1 -1
- {botversion_sdk-1.0.6/botversion_sdk → botversion_sdk-1.1.7}/setup.py +1 -1
- botversion_sdk-1.0.6/botversion_sdk/interceptor.py +0 -257
- botversion_sdk-1.0.6/setup.py +0 -42
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk.egg-info/dependency_links.txt +0 -0
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk.egg-info/entry_points.txt +0 -0
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/botversion_sdk.egg-info/top_level.txt +0 -0
- {botversion_sdk-1.0.6 → botversion_sdk-1.1.7}/setup.cfg +0 -0
|
@@ -10,6 +10,14 @@ from .interceptor import (
|
|
|
10
10
|
attach_fastapi_interceptor,
|
|
11
11
|
attach_flask_interceptor,
|
|
12
12
|
attach_django_interceptor,
|
|
13
|
+
attach_starlette_interceptor,
|
|
14
|
+
attach_sanic_interceptor,
|
|
15
|
+
attach_falcon_interceptor,
|
|
16
|
+
attach_bottle_interceptor,
|
|
17
|
+
attach_aiohttp_interceptor,
|
|
18
|
+
attach_tornado_interceptor,
|
|
19
|
+
attach_pyramid_interceptor,
|
|
20
|
+
attach_cherrypy_interceptor,
|
|
13
21
|
)
|
|
14
22
|
|
|
15
23
|
_initialized = False
|
|
@@ -55,6 +63,23 @@ def init(app=None, api_key=None, **options):
|
|
|
55
63
|
attach_flask_interceptor(app, _client, interceptor_options)
|
|
56
64
|
elif framework == "django":
|
|
57
65
|
attach_django_interceptor(_client, interceptor_options)
|
|
66
|
+
# ── NEW ───────────────────────────────────────────────────────
|
|
67
|
+
elif framework == "starlette":
|
|
68
|
+
attach_starlette_interceptor(app, _client, interceptor_options)
|
|
69
|
+
elif framework == "sanic":
|
|
70
|
+
attach_sanic_interceptor(app, _client, interceptor_options)
|
|
71
|
+
elif framework == "falcon":
|
|
72
|
+
attach_falcon_interceptor(app, _client, interceptor_options)
|
|
73
|
+
elif framework == "bottle":
|
|
74
|
+
attach_bottle_interceptor(app, _client, interceptor_options)
|
|
75
|
+
elif framework == "aiohttp":
|
|
76
|
+
attach_aiohttp_interceptor(app, _client, interceptor_options)
|
|
77
|
+
elif framework == "tornado":
|
|
78
|
+
attach_tornado_interceptor(app, _client, interceptor_options)
|
|
79
|
+
elif framework == "pyramid":
|
|
80
|
+
attach_pyramid_interceptor(app, _client, interceptor_options)
|
|
81
|
+
elif framework == "cherrypy":
|
|
82
|
+
attach_cherrypy_interceptor(app, _client, interceptor_options)
|
|
58
83
|
return
|
|
59
84
|
|
|
60
85
|
_initialized = True
|
|
@@ -96,6 +121,23 @@ def init(app=None, api_key=None, **options):
|
|
|
96
121
|
attach_flask_interceptor(app, _client, interceptor_options)
|
|
97
122
|
elif framework == "django":
|
|
98
123
|
attach_django_interceptor(_client, interceptor_options)
|
|
124
|
+
# ── NEW ───────────────────────────────────────────────────────────────────
|
|
125
|
+
elif framework == "starlette":
|
|
126
|
+
attach_starlette_interceptor(app, _client, interceptor_options)
|
|
127
|
+
elif framework == "sanic":
|
|
128
|
+
attach_sanic_interceptor(app, _client, interceptor_options)
|
|
129
|
+
elif framework == "falcon":
|
|
130
|
+
attach_falcon_interceptor(app, _client, interceptor_options)
|
|
131
|
+
elif framework == "bottle":
|
|
132
|
+
attach_bottle_interceptor(app, _client, interceptor_options)
|
|
133
|
+
elif framework == "aiohttp":
|
|
134
|
+
attach_aiohttp_interceptor(app, _client, interceptor_options)
|
|
135
|
+
elif framework == "tornado":
|
|
136
|
+
attach_tornado_interceptor(app, _client, interceptor_options)
|
|
137
|
+
elif framework == "pyramid":
|
|
138
|
+
attach_pyramid_interceptor(app, _client, interceptor_options)
|
|
139
|
+
elif framework == "cherrypy":
|
|
140
|
+
attach_cherrypy_interceptor(app, _client, interceptor_options)
|
|
99
141
|
else:
|
|
100
142
|
return
|
|
101
143
|
|
|
@@ -110,8 +152,8 @@ def init(app=None, api_key=None, **options):
|
|
|
110
152
|
elif framework == "django":
|
|
111
153
|
endpoints = scan_routes(None, "django")
|
|
112
154
|
|
|
113
|
-
|
|
114
|
-
|
|
155
|
+
# For any other framework with no app object, skip backend scan
|
|
156
|
+
# but still continue to frontend scan below
|
|
115
157
|
|
|
116
158
|
if endpoints:
|
|
117
159
|
_client.register_endpoints_now(endpoints)
|
|
@@ -127,17 +169,19 @@ def init(app=None, api_key=None, **options):
|
|
|
127
169
|
_client.register_route_patterns(route_patterns)
|
|
128
170
|
|
|
129
171
|
if framework == "flask":
|
|
130
|
-
# Scan on startup
|
|
131
172
|
with app.app_context():
|
|
132
|
-
threading.Thread(target=_run_scan, daemon=
|
|
173
|
+
t = threading.Thread(target=_run_scan, daemon=False)
|
|
174
|
+
t.start()
|
|
175
|
+
t.join(timeout=15)
|
|
133
176
|
app._botversion_scanned = True
|
|
134
177
|
|
|
135
|
-
# Keep after_request as fallback for runtime detection
|
|
136
178
|
@app.after_request
|
|
137
179
|
def _botversion_first_scan(response):
|
|
138
180
|
if not getattr(app, '_botversion_scanned', False):
|
|
139
181
|
app._botversion_scanned = True
|
|
140
|
-
threading.Thread(target=_run_scan, daemon=
|
|
182
|
+
t = threading.Thread(target=_run_scan, daemon=False)
|
|
183
|
+
t.start()
|
|
184
|
+
t.join(timeout=15)
|
|
141
185
|
return response
|
|
142
186
|
|
|
143
187
|
elif framework == "fastapi":
|
|
@@ -145,26 +189,37 @@ def init(app=None, api_key=None, **options):
|
|
|
145
189
|
async def _botversion_startup_scan():
|
|
146
190
|
if not getattr(app, '_botversion_scanned', False):
|
|
147
191
|
app._botversion_scanned = True
|
|
148
|
-
threading.Thread(target=_run_scan, daemon=
|
|
192
|
+
t = threading.Thread(target=_run_scan, daemon=False)
|
|
193
|
+
t.start()
|
|
194
|
+
t.join(timeout=15)
|
|
149
195
|
|
|
150
|
-
# Keep middleware as fallback for runtime detection
|
|
151
196
|
@app.middleware("http")
|
|
152
197
|
async def _botversion_first_scan(request, call_next):
|
|
153
198
|
if not getattr(app, '_botversion_scanned', False):
|
|
154
199
|
app._botversion_scanned = True
|
|
155
|
-
threading.Thread(target=_run_scan, daemon=
|
|
200
|
+
t = threading.Thread(target=_run_scan, daemon=False)
|
|
201
|
+
t.start()
|
|
202
|
+
t.join(timeout=15)
|
|
156
203
|
return await call_next(request)
|
|
157
204
|
|
|
158
205
|
elif framework == "django":
|
|
159
206
|
try:
|
|
160
207
|
from django.apps import apps
|
|
161
208
|
if apps.ready:
|
|
162
|
-
threading.Thread(target=_run_scan, daemon=
|
|
209
|
+
t = threading.Thread(target=_run_scan, daemon=False)
|
|
210
|
+
t.start()
|
|
211
|
+
t.join(timeout=15)
|
|
163
212
|
except Exception:
|
|
164
|
-
t = threading.Timer(
|
|
165
|
-
t.daemon =
|
|
213
|
+
t = threading.Timer(3.0, _run_scan)
|
|
214
|
+
t.daemon = False
|
|
166
215
|
t.start()
|
|
167
216
|
|
|
217
|
+
elif framework in ("starlette", "sanic", "falcon", "bottle",
|
|
218
|
+
"aiohttp", "tornado", "pyramid", "cherrypy"):
|
|
219
|
+
t = threading.Timer(3.0, _run_scan)
|
|
220
|
+
t.daemon = False
|
|
221
|
+
t.start()
|
|
222
|
+
|
|
168
223
|
|
|
169
224
|
def get_endpoints():
|
|
170
225
|
"""Get all registered endpoints for this workspace."""
|
|
@@ -185,11 +240,32 @@ def register_endpoint(endpoint):
|
|
|
185
240
|
def _detect_framework(app):
|
|
186
241
|
if app is not None:
|
|
187
242
|
app_type = type(app).__module__ + "." + type(app).__name__
|
|
243
|
+
|
|
244
|
+
# ── Existing ──────────────────────────────────────────────────────
|
|
188
245
|
if "fastapi" in app_type.lower():
|
|
189
246
|
return "fastapi"
|
|
190
247
|
if "flask" in app_type.lower():
|
|
191
248
|
return "flask"
|
|
192
249
|
|
|
250
|
+
# ── NEW ───────────────────────────────────────────────────────────
|
|
251
|
+
if "starlette" in app_type.lower():
|
|
252
|
+
return "starlette"
|
|
253
|
+
if "sanic" in app_type.lower():
|
|
254
|
+
return "sanic"
|
|
255
|
+
if "falcon" in app_type.lower():
|
|
256
|
+
return "falcon"
|
|
257
|
+
if "bottle" in app_type.lower():
|
|
258
|
+
return "bottle"
|
|
259
|
+
if "aiohttp" in app_type.lower():
|
|
260
|
+
return "aiohttp"
|
|
261
|
+
if "tornado" in app_type.lower():
|
|
262
|
+
return "tornado"
|
|
263
|
+
if "pyramid" in app_type.lower():
|
|
264
|
+
return "pyramid"
|
|
265
|
+
if "cherrypy" in app_type.lower():
|
|
266
|
+
return "cherrypy"
|
|
267
|
+
|
|
268
|
+
# ── No app object passed — try detecting from imported modules ────────
|
|
193
269
|
if app is None:
|
|
194
270
|
if "django" in sys.modules:
|
|
195
271
|
try:
|
|
@@ -199,11 +275,29 @@ def _detect_framework(app):
|
|
|
199
275
|
except Exception:
|
|
200
276
|
pass
|
|
201
277
|
|
|
278
|
+
# ── Fallback — check sys.modules ──────────────────────────────────────
|
|
202
279
|
if "fastapi" in sys.modules:
|
|
203
280
|
return "fastapi"
|
|
204
281
|
if "flask" in sys.modules:
|
|
205
282
|
return "flask"
|
|
206
283
|
if "django" in sys.modules:
|
|
207
284
|
return "django"
|
|
285
|
+
# ── NEW fallbacks ─────────────────────────────────────────────────────
|
|
286
|
+
if "starlette" in sys.modules:
|
|
287
|
+
return "starlette"
|
|
288
|
+
if "sanic" in sys.modules:
|
|
289
|
+
return "sanic"
|
|
290
|
+
if "falcon" in sys.modules:
|
|
291
|
+
return "falcon"
|
|
292
|
+
if "bottle" in sys.modules:
|
|
293
|
+
return "bottle"
|
|
294
|
+
if "aiohttp" in sys.modules:
|
|
295
|
+
return "aiohttp"
|
|
296
|
+
if "tornado" in sys.modules:
|
|
297
|
+
return "tornado"
|
|
298
|
+
if "pyramid" in sys.modules:
|
|
299
|
+
return "pyramid"
|
|
300
|
+
if "cherrypy" in sys.modules:
|
|
301
|
+
return "cherrypy"
|
|
208
302
|
|
|
209
303
|
return None
|
|
File without changes
|