dc-python-sdk 1.5.23__tar.gz → 1.5.25__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.
- {dc_python_sdk-1.5.23/src/dc_python_sdk.egg-info → dc_python_sdk-1.5.25}/PKG-INFO +1 -1
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/pyproject.toml +1 -1
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/setup.cfg +1 -1
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25/src/dc_python_sdk.egg-info}/PKG-INFO +1 -1
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/cli.py +7 -5
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/ai_http.py +197 -168
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/server.py +17 -7
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/LICENSE +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/README.md +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/SOURCES.txt +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/dependency_links.txt +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/entry_points.txt +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/requires.txt +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/top_level.txt +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/__init__.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/app.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/errors.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/handler.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/__init__.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/ai.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/mapping.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/models/__init__.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/models/enums.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/models/errors.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/models/log_templates.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/models/pipeline_details.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/pipeline.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/__init__.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/api.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/aws.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/environment.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/loader.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/logger.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/src/services/session.py +0 -0
- {dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_sdk/types.py +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from importlib.metadata import version
|
|
3
|
+
import os
|
|
3
4
|
|
|
4
5
|
def get_arg(name, default=None):
|
|
5
6
|
if name in sys.argv:
|
|
@@ -15,15 +16,13 @@ def main():
|
|
|
15
16
|
|
|
16
17
|
command = sys.argv[1]
|
|
17
18
|
|
|
18
|
-
port = int(get_arg("--port", 5000))
|
|
19
|
-
|
|
20
19
|
print("version: ", version("dc-python-sdk"))
|
|
21
20
|
|
|
22
21
|
print(f"[DC SDK] Command: {command}")
|
|
23
22
|
|
|
24
23
|
if command == "http":
|
|
25
24
|
from dc_sdk.src.server import start_server
|
|
26
|
-
start_server(
|
|
25
|
+
start_server()
|
|
27
26
|
|
|
28
27
|
elif command == "ai":
|
|
29
28
|
from dc_sdk.src.ai import start_ai
|
|
@@ -31,8 +30,11 @@ def main():
|
|
|
31
30
|
|
|
32
31
|
elif command == "ai-http":
|
|
33
32
|
from dc_sdk.src.ai_http import start_ai_http
|
|
34
|
-
start_ai_http(
|
|
33
|
+
start_ai_http()
|
|
35
34
|
|
|
36
35
|
else:
|
|
37
36
|
print(f"Unknown command: {command}")
|
|
38
|
-
sys.exit(1)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
main()
|
|
@@ -20,15 +20,23 @@ app = FastAPI()
|
|
|
20
20
|
|
|
21
21
|
_DEFAULT_PROCESS_TTL_SECONDS = 600.0
|
|
22
22
|
|
|
23
|
+
# Default ports: connector HTTP (dc-sdk http) 5000, AI FastAPI 5001, code-server 5002.
|
|
24
|
+
CONNECTOR_PORT = os.getenv("CONNECTOR_PORT", 5000)
|
|
25
|
+
AI_PORT = os.getenv("AI_PORT", 5001)
|
|
26
|
+
CODE_SERVER_PORT = os.getenv("CODE_SERVER_PORT", 5002)
|
|
27
|
+
|
|
23
28
|
client = None
|
|
24
29
|
workspace = os.getenv("WORKSPACE", "/workspace")
|
|
25
|
-
port_for_connector = 5000
|
|
26
30
|
|
|
27
31
|
# Process-wide TTL for ai-http (see DC_SDK_TTL_SECONDS); exposed in /session-info.
|
|
28
32
|
process_ttl_seconds: Optional[float] = None
|
|
29
33
|
process_ttl_deadline_unix: Optional[float] = None
|
|
30
34
|
_process_ttl_timer: Optional[threading.Timer] = None
|
|
31
35
|
|
|
36
|
+
# Long-lived `dc-sdk http` subprocess (uvicorn with CONNECTOR_HTTP_RELOAD reloads connector.py).
|
|
37
|
+
_connector_proc: Optional[subprocess.Popen] = None
|
|
38
|
+
_connector_lock = threading.Lock()
|
|
39
|
+
|
|
32
40
|
# -----------------------------
|
|
33
41
|
# MODELS
|
|
34
42
|
# -----------------------------
|
|
@@ -91,40 +99,68 @@ def _parse_process_ttl_seconds() -> float:
|
|
|
91
99
|
return 0.0
|
|
92
100
|
return v
|
|
93
101
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
def _wait_connector_healthy() -> None:
|
|
103
|
+
for _ in range(50):
|
|
104
|
+
try:
|
|
105
|
+
res = requests.get(f"http://localhost:{CONNECTOR_PORT}/health", timeout=2)
|
|
106
|
+
if res.status_code == 200:
|
|
107
|
+
logger.info("Connector ready on port %s", CONNECTOR_PORT)
|
|
108
|
+
return
|
|
109
|
+
except Exception:
|
|
110
|
+
logger.debug("Health check not ready yet on port %s", CONNECTOR_PORT)
|
|
111
|
+
time.sleep(0.1)
|
|
112
|
+
raise RuntimeError(
|
|
113
|
+
f"Connector failed to become healthy on port {CONNECTOR_PORT} within timeout"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _start_connector_subprocess_unlocked() -> None:
|
|
118
|
+
global _connector_proc, workspace
|
|
119
|
+
env = os.environ.copy()
|
|
120
|
+
env["CONNECTOR_HTTP_RELOAD"] = "1"
|
|
97
121
|
proc = subprocess.Popen(
|
|
98
|
-
["dc-sdk", "http"
|
|
122
|
+
["dc-sdk", "http"],
|
|
99
123
|
cwd=workspace,
|
|
124
|
+
env=env,
|
|
100
125
|
stdout=subprocess.DEVNULL,
|
|
101
|
-
stderr=subprocess.DEVNULL
|
|
126
|
+
stderr=subprocess.DEVNULL,
|
|
102
127
|
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
try:
|
|
129
|
+
_wait_connector_healthy()
|
|
130
|
+
except Exception:
|
|
131
|
+
proc.terminate()
|
|
106
132
|
try:
|
|
107
|
-
|
|
108
|
-
if res.status_code == 200:
|
|
109
|
-
logger.info("Connector ready on port %s", port_for_connector)
|
|
110
|
-
return {"process": proc, "port": port_for_connector}
|
|
133
|
+
proc.wait(timeout=5)
|
|
111
134
|
except Exception:
|
|
112
|
-
|
|
113
|
-
|
|
135
|
+
pass
|
|
136
|
+
raise
|
|
137
|
+
_connector_proc = proc
|
|
114
138
|
|
|
115
|
-
logger.error("Connector failed to become healthy on port %s within timeout", port_for_connector)
|
|
116
|
-
proc.terminate()
|
|
117
|
-
raise Exception("Failed to start connector")
|
|
118
139
|
|
|
119
|
-
def
|
|
140
|
+
def _stop_connector_subprocess_unlocked() -> None:
|
|
141
|
+
global _connector_proc
|
|
142
|
+
proc = _connector_proc
|
|
143
|
+
_connector_proc = None
|
|
144
|
+
if proc is None:
|
|
145
|
+
return
|
|
120
146
|
try:
|
|
121
|
-
|
|
122
|
-
|
|
147
|
+
proc.terminate()
|
|
148
|
+
proc.wait(timeout=15)
|
|
123
149
|
logger.debug("Connector subprocess stopped")
|
|
124
150
|
except Exception:
|
|
125
151
|
logger.debug("Error stopping connector subprocess", exc_info=True)
|
|
126
152
|
|
|
127
|
-
|
|
153
|
+
|
|
154
|
+
def start_connector_http_server() -> None:
|
|
155
|
+
"""Start the connector HTTP child once; restart if the previous child exited."""
|
|
156
|
+
with _connector_lock:
|
|
157
|
+
if _connector_proc is not None and _connector_proc.poll() is None:
|
|
158
|
+
return
|
|
159
|
+
_stop_connector_subprocess_unlocked()
|
|
160
|
+
_start_connector_subprocess_unlocked()
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def invoke(method, session_id=None, credentials=None, params=None):
|
|
128
164
|
payload = {
|
|
129
165
|
"method": method,
|
|
130
166
|
"session_id": session_id,
|
|
@@ -132,8 +168,8 @@ def invoke(port, method, session_id=None, credentials=None, params=None):
|
|
|
132
168
|
"params": params or {}
|
|
133
169
|
}
|
|
134
170
|
|
|
135
|
-
logger.debug("invoke port=%s method=%s session_id=%s",
|
|
136
|
-
res = requests.post(f"http://localhost:{
|
|
171
|
+
logger.debug("invoke port=%s method=%s session_id=%s", CONNECTOR_PORT, method, session_id)
|
|
172
|
+
res = requests.post(f"http://localhost:{CONNECTOR_PORT}/invoke", json=payload)
|
|
137
173
|
if res.status_code != 200:
|
|
138
174
|
logger.warning(
|
|
139
175
|
"invoke returned HTTP %s for method=%s", res.status_code, method
|
|
@@ -208,166 +244,159 @@ def run_test(
|
|
|
208
244
|
connector_context: ConnectorContext,
|
|
209
245
|
test_object_ids: Optional[List[str]] = None,
|
|
210
246
|
):
|
|
211
|
-
runtime = start_connector()
|
|
212
247
|
requested_ids = [_canon_object_id(x) for x in (test_object_ids or []) if _canon_object_id(x)]
|
|
213
248
|
print(requested_ids)
|
|
214
249
|
|
|
215
|
-
|
|
216
|
-
session_id = None
|
|
250
|
+
session_id = None
|
|
217
251
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
252
|
+
# authenticate
|
|
253
|
+
res = invoke("authenticate", None, credentials)
|
|
254
|
+
if res.get("results") is not True:
|
|
255
|
+
logger.warning("run_test failed at stage=authenticate")
|
|
256
|
+
return False, "authenticate", res
|
|
223
257
|
|
|
224
|
-
|
|
258
|
+
session_id = res.get("session_id")
|
|
225
259
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
logger.warning(
|
|
243
|
-
"run_test failed: test_object_ids disjoint from get_objects"
|
|
244
|
-
)
|
|
245
|
-
return False, "get_objects", {
|
|
246
|
-
"message": (
|
|
247
|
-
f"objects_dynamic is true: none of test_object_ids {requested_ids} "
|
|
248
|
-
f"appear in get_objects results {api_ids}."
|
|
249
|
-
),
|
|
250
|
-
}
|
|
251
|
-
ids_for_fields = wanted
|
|
252
|
-
else:
|
|
253
|
-
ids_for_fields = list(api_ids)
|
|
254
|
-
else:
|
|
255
|
-
if not requested_ids:
|
|
260
|
+
# get_objects
|
|
261
|
+
res = invoke("get_objects", session_id)
|
|
262
|
+
if not isinstance(res.get("results"), list):
|
|
263
|
+
logger.warning("run_test failed at stage=get_objects (invalid results type)")
|
|
264
|
+
return False, "get_objects", res
|
|
265
|
+
|
|
266
|
+
objects = res["results"]
|
|
267
|
+
api_ids = _object_ids_from_get_objects_results(objects)
|
|
268
|
+
dynamic = connector_context.objects_dynamic
|
|
269
|
+
|
|
270
|
+
if dynamic:
|
|
271
|
+
if api_ids:
|
|
272
|
+
if requested_ids:
|
|
273
|
+
api_set = set(api_ids)
|
|
274
|
+
wanted = [x for x in requested_ids if x in api_set]
|
|
275
|
+
if not wanted:
|
|
256
276
|
logger.warning(
|
|
257
|
-
"run_test failed:
|
|
277
|
+
"run_test failed: test_object_ids disjoint from get_objects"
|
|
258
278
|
)
|
|
259
279
|
return False, "get_objects", {
|
|
260
280
|
"message": (
|
|
261
|
-
"objects_dynamic is true:
|
|
262
|
-
"
|
|
281
|
+
f"objects_dynamic is true: none of test_object_ids {requested_ids} "
|
|
282
|
+
f"appear in get_objects results {api_ids}."
|
|
263
283
|
),
|
|
264
284
|
}
|
|
265
|
-
ids_for_fields =
|
|
285
|
+
ids_for_fields = wanted
|
|
286
|
+
else:
|
|
287
|
+
ids_for_fields = list(api_ids)
|
|
266
288
|
else:
|
|
267
|
-
print(requested_ids)
|
|
268
289
|
if not requested_ids:
|
|
269
|
-
logger.warning(
|
|
290
|
+
logger.warning(
|
|
291
|
+
"run_test failed: objects_dynamic with empty get_objects and no test_object_ids"
|
|
292
|
+
)
|
|
270
293
|
return False, "get_objects", {
|
|
271
294
|
"message": (
|
|
272
|
-
"objects_dynamic is
|
|
273
|
-
"
|
|
295
|
+
"objects_dynamic is true: get_objects returned no objects. "
|
|
296
|
+
"Provide test_object_ids in the request to probe get_fields and get_data."
|
|
274
297
|
),
|
|
275
298
|
}
|
|
276
|
-
if not objects:
|
|
277
|
-
logger.warning("run_test failed at stage=get_objects (empty list)")
|
|
278
|
-
return False, "get_objects", {"message": "No objects returned from get_objects"}
|
|
279
|
-
|
|
280
299
|
ids_for_fields = list(requested_ids)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
300
|
+
else:
|
|
301
|
+
print(requested_ids)
|
|
302
|
+
if not requested_ids:
|
|
303
|
+
logger.warning("run_test failed: static objects require test_object_ids")
|
|
284
304
|
return False, "get_objects", {
|
|
285
|
-
"message": "No object ids available to test get_fields (empty candidate list).",
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
objects_with_fields: List[Tuple[str, List[Any]]] = []
|
|
289
|
-
last_fields_payload: Any = None
|
|
290
|
-
|
|
291
|
-
print(ids_for_fields)
|
|
292
|
-
|
|
293
|
-
for object_id in ids_for_fields:
|
|
294
|
-
res = invoke(
|
|
295
|
-
runtime["port"],
|
|
296
|
-
"get_fields",
|
|
297
|
-
session_id,
|
|
298
|
-
params={"object_id": object_id},
|
|
299
|
-
)
|
|
300
|
-
if not isinstance(res.get("results"), list):
|
|
301
|
-
logger.warning(
|
|
302
|
-
"run_test failed at stage=get_fields (invalid results type) object_id=%s",
|
|
303
|
-
object_id,
|
|
304
|
-
)
|
|
305
|
-
return False, "get_fields", res
|
|
306
|
-
|
|
307
|
-
fields = res["results"]
|
|
308
|
-
last_fields_payload = res
|
|
309
|
-
logger.info("get_fields results for object_id=%s: %s", object_id, len(fields))
|
|
310
|
-
if fields:
|
|
311
|
-
fids = [
|
|
312
|
-
f.get("field_id") or f.get("id")
|
|
313
|
-
for f in fields[:5]
|
|
314
|
-
if (f.get("field_id") or f.get("id")) is not None
|
|
315
|
-
]
|
|
316
|
-
if fids:
|
|
317
|
-
objects_with_fields.append((object_id, fids))
|
|
318
|
-
|
|
319
|
-
if not objects_with_fields:
|
|
320
|
-
logger.warning(
|
|
321
|
-
"run_test failed: no fields on any object tried ids=%s",
|
|
322
|
-
ids_for_fields,
|
|
323
|
-
)
|
|
324
|
-
return False, "get_fields", {
|
|
325
305
|
"message": (
|
|
326
|
-
|
|
327
|
-
"
|
|
306
|
+
"objects_dynamic is false: test_object_ids is required and must list "
|
|
307
|
+
"object ids you expect get_objects to return."
|
|
328
308
|
),
|
|
329
|
-
"last_invoke": last_fields_payload,
|
|
330
309
|
}
|
|
310
|
+
if not objects:
|
|
311
|
+
logger.warning("run_test failed at stage=get_objects (empty list)")
|
|
312
|
+
return False, "get_objects", {"message": "No objects returned from get_objects"}
|
|
331
313
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
},
|
|
343
|
-
)
|
|
344
|
-
last_data_res = res
|
|
345
|
-
if not isinstance(res.get("results"), dict):
|
|
346
|
-
logger.warning(
|
|
347
|
-
"run_test failed at stage=get_data (invalid results type) object_id=%s",
|
|
348
|
-
object_id,
|
|
349
|
-
)
|
|
350
|
-
return False, "get_data", res
|
|
314
|
+
ids_for_fields = list(requested_ids)
|
|
315
|
+
|
|
316
|
+
if not ids_for_fields:
|
|
317
|
+
logger.warning("run_test failed: no object ids to probe")
|
|
318
|
+
return False, "get_objects", {
|
|
319
|
+
"message": "No object ids available to test get_fields (empty candidate list).",
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
objects_with_fields: List[Tuple[str, List[Any]]] = []
|
|
323
|
+
last_fields_payload: Any = None
|
|
351
324
|
|
|
352
|
-
|
|
353
|
-
rows = payload.get("data")
|
|
354
|
-
if isinstance(rows, list) and len(rows) > 0:
|
|
355
|
-
logger.info("run_test completed successfully object_id=%s, rows retrieved=%s", object_id, len(rows))
|
|
356
|
-
return True, None, None
|
|
325
|
+
print(ids_for_fields)
|
|
357
326
|
|
|
327
|
+
for object_id in ids_for_fields:
|
|
328
|
+
res = invoke(
|
|
329
|
+
"get_fields",
|
|
330
|
+
session_id,
|
|
331
|
+
params={"object_id": object_id},
|
|
332
|
+
)
|
|
333
|
+
if not isinstance(res.get("results"), list):
|
|
334
|
+
logger.warning(
|
|
335
|
+
"run_test failed at stage=get_fields (invalid results type) object_id=%s",
|
|
336
|
+
object_id,
|
|
337
|
+
)
|
|
338
|
+
return False, "get_fields", res
|
|
339
|
+
|
|
340
|
+
fields = res["results"]
|
|
341
|
+
last_fields_payload = res
|
|
342
|
+
logger.info("get_fields results for object_id=%s: %s", object_id, len(fields))
|
|
343
|
+
if fields:
|
|
344
|
+
fids = [
|
|
345
|
+
f.get("field_id") or f.get("id")
|
|
346
|
+
for f in fields[:5]
|
|
347
|
+
if (f.get("field_id") or f.get("id")) is not None
|
|
348
|
+
]
|
|
349
|
+
if fids:
|
|
350
|
+
objects_with_fields.append((object_id, fids))
|
|
351
|
+
|
|
352
|
+
if not objects_with_fields:
|
|
358
353
|
logger.warning(
|
|
359
|
-
"run_test failed:
|
|
354
|
+
"run_test failed: no fields on any object tried ids=%s",
|
|
355
|
+
ids_for_fields,
|
|
360
356
|
)
|
|
361
|
-
return False, "
|
|
357
|
+
return False, "get_fields", {
|
|
362
358
|
"message": (
|
|
363
|
-
f"
|
|
364
|
-
|
|
359
|
+
f"get_fields returned no usable fields for any tested object_id(s): {ids_for_fields}. "
|
|
360
|
+
"Verify object ids and connector field discovery."
|
|
365
361
|
),
|
|
366
|
-
"last_invoke":
|
|
362
|
+
"last_invoke": last_fields_payload,
|
|
367
363
|
}
|
|
368
364
|
|
|
369
|
-
|
|
370
|
-
|
|
365
|
+
last_data_res: Any = None
|
|
366
|
+
for object_id, field_ids in objects_with_fields:
|
|
367
|
+
res = invoke(
|
|
368
|
+
"get_data",
|
|
369
|
+
session_id,
|
|
370
|
+
params={
|
|
371
|
+
"object_id": object_id,
|
|
372
|
+
"field_ids": field_ids,
|
|
373
|
+
"n_rows": 5,
|
|
374
|
+
},
|
|
375
|
+
)
|
|
376
|
+
last_data_res = res
|
|
377
|
+
if not isinstance(res.get("results"), dict):
|
|
378
|
+
logger.warning(
|
|
379
|
+
"run_test failed at stage=get_data (invalid results type) object_id=%s",
|
|
380
|
+
object_id,
|
|
381
|
+
)
|
|
382
|
+
return False, "get_data", res
|
|
383
|
+
|
|
384
|
+
payload = res["results"]
|
|
385
|
+
rows = payload.get("data")
|
|
386
|
+
if isinstance(rows, list) and len(rows) > 0:
|
|
387
|
+
logger.info("run_test completed successfully object_id=%s, rows retrieved=%s", object_id, len(rows))
|
|
388
|
+
return True, None, None
|
|
389
|
+
|
|
390
|
+
logger.warning(
|
|
391
|
+
"run_test failed: get_data returned no rows for any object with fields"
|
|
392
|
+
)
|
|
393
|
+
return False, "get_data", {
|
|
394
|
+
"message": (
|
|
395
|
+
f"get_data returned no rows for any object that had fields "
|
|
396
|
+
f"(tried {len(objects_with_fields)} object(s))."
|
|
397
|
+
),
|
|
398
|
+
"last_invoke": last_data_res,
|
|
399
|
+
}
|
|
371
400
|
|
|
372
401
|
|
|
373
402
|
def _validate_static_requires_object_ids(
|
|
@@ -710,8 +739,7 @@ def clone_repo():
|
|
|
710
739
|
subprocess.run(["git", "-C", workspace, "checkout", branch], check=True)
|
|
711
740
|
subprocess.run(["git", "-C", workspace, "pull"], check=True)
|
|
712
741
|
|
|
713
|
-
def run_code_server(
|
|
714
|
-
global port_for_connector
|
|
742
|
+
def run_code_server():
|
|
715
743
|
logger.info("code-server path: %s", shutil.which("code-server"))
|
|
716
744
|
|
|
717
745
|
# ✅ Ensure config dir exists
|
|
@@ -720,7 +748,7 @@ def run_code_server(port):
|
|
|
720
748
|
# ✅ Write code-server config
|
|
721
749
|
with open("/root/.config/code-server/config.yaml", "w") as f:
|
|
722
750
|
f.write(
|
|
723
|
-
f"bind-addr: 0.0.0.0:{
|
|
751
|
+
f"bind-addr: 0.0.0.0:{CODE_SERVER_PORT}\n"
|
|
724
752
|
"auth: none\n"
|
|
725
753
|
)
|
|
726
754
|
|
|
@@ -755,15 +783,12 @@ def run_code_server(port):
|
|
|
755
783
|
|
|
756
784
|
return code_server_proc
|
|
757
785
|
|
|
758
|
-
def start_ai_http(
|
|
786
|
+
def start_ai_http(start_code_server=True):
|
|
759
787
|
global client
|
|
760
788
|
global workspace
|
|
761
789
|
global process_ttl_seconds
|
|
762
790
|
global process_ttl_deadline_unix
|
|
763
791
|
global _process_ttl_timer
|
|
764
|
-
global port_for_connector
|
|
765
|
-
|
|
766
|
-
port_for_connector = connector_port
|
|
767
792
|
|
|
768
793
|
process_ttl_seconds = None
|
|
769
794
|
process_ttl_deadline_unix = None
|
|
@@ -803,13 +828,13 @@ def start_ai_http(connector_port=5000, start_code_server=True):
|
|
|
803
828
|
)
|
|
804
829
|
|
|
805
830
|
api_key = os.getenv("OPENAI_API_KEY")
|
|
806
|
-
ai_port = int(os.getenv("AI_PORT", 5050))
|
|
807
|
-
connector_server_port = int(os.getenv("CONNECTOR_SERVER_PORT", 5001))
|
|
808
831
|
|
|
809
832
|
clone_repo()
|
|
833
|
+
start_connector_http_server()
|
|
810
834
|
|
|
835
|
+
code_server_proc = None
|
|
811
836
|
if start_code_server:
|
|
812
|
-
code_server_proc = run_code_server(
|
|
837
|
+
code_server_proc = run_code_server()
|
|
813
838
|
|
|
814
839
|
def shutdown():
|
|
815
840
|
global _process_ttl_timer
|
|
@@ -818,8 +843,11 @@ def start_ai_http(connector_port=5000, start_code_server=True):
|
|
|
818
843
|
if tm is not None:
|
|
819
844
|
tm.cancel()
|
|
820
845
|
logger.info("Shutting down code-server...")
|
|
821
|
-
if code_server_proc:
|
|
846
|
+
if code_server_proc is not None:
|
|
822
847
|
code_server_proc.terminate()
|
|
848
|
+
logger.info("Shutting down connector HTTP...")
|
|
849
|
+
with _connector_lock:
|
|
850
|
+
_stop_connector_subprocess_unlocked()
|
|
823
851
|
|
|
824
852
|
ttl_shutdown_holder["fn"] = shutdown
|
|
825
853
|
|
|
@@ -837,18 +865,19 @@ def start_ai_http(connector_port=5000, start_code_server=True):
|
|
|
837
865
|
|
|
838
866
|
client = OpenAI(api_key=api_key)
|
|
839
867
|
|
|
840
|
-
logger.info("Starting AI HTTP controller on 0.0.0.0:%s",
|
|
868
|
+
logger.info("Starting AI HTTP controller on 0.0.0.0:%s", AI_PORT)
|
|
841
869
|
|
|
842
870
|
import uvicorn
|
|
843
|
-
uvicorn.run(app, host="0.0.0.0", port=
|
|
871
|
+
uvicorn.run(app, host="0.0.0.0", port=AI_PORT)
|
|
844
872
|
|
|
845
873
|
@app.get("/session-info")
|
|
846
874
|
def session_info():
|
|
847
875
|
out: Dict[str, Any] = {
|
|
848
876
|
"workspace": workspace,
|
|
849
|
-
"
|
|
850
|
-
"
|
|
851
|
-
"
|
|
877
|
+
"connector_port": CONNECTOR_PORT,
|
|
878
|
+
"ai_port": AI_PORT,
|
|
879
|
+
"code_server_port": CODE_SERVER_PORT,
|
|
880
|
+
"api_base": f"http://localhost:{AI_PORT}",
|
|
852
881
|
}
|
|
853
882
|
if process_ttl_seconds is not None and process_ttl_deadline_unix is not None:
|
|
854
883
|
out["ttl_seconds"] = process_ttl_seconds
|
|
@@ -88,11 +88,21 @@ def invoke(req: InvokeRequest):
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def start_server(
|
|
91
|
+
def start_server():
|
|
92
92
|
import uvicorn
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
|
|
94
|
+
listen = int(os.getenv("CONNECTOR_PORT", 5000))
|
|
95
|
+
workspace = os.getenv("WORKSPACE", os.getcwd())
|
|
96
|
+
connector_src = os.path.join(workspace, "src")
|
|
97
|
+
use_reload = os.getenv("CONNECTOR_HTTP_RELOAD", "0").lower() in ("1", "true", "yes")
|
|
98
|
+
|
|
99
|
+
kw: Dict[str, Any] = {
|
|
100
|
+
"host": "0.0.0.0",
|
|
101
|
+
"port": listen,
|
|
102
|
+
}
|
|
103
|
+
if use_reload:
|
|
104
|
+
kw["reload"] = True
|
|
105
|
+
watch = connector_src if os.path.isdir(connector_src) else workspace
|
|
106
|
+
kw["reload_dirs"] = [os.path.abspath(watch)]
|
|
107
|
+
|
|
108
|
+
uvicorn.run("dc_sdk.src.server:app", **kw)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dc_python_sdk-1.5.23 → dc_python_sdk-1.5.25}/src/dc_python_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|