darkpyonix 0.1.0__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.
- darkpyonix/__init__.py +0 -0
- darkpyonix/__main__.py +0 -0
- darkpyonix/kernel/__init__.py +0 -0
- darkpyonix/kernel/__main__.py +0 -0
- darkpyonix/manager/app.py +432 -0
- darkpyonix-0.1.0.dist-info/METADATA +36 -0
- darkpyonix-0.1.0.dist-info/RECORD +10 -0
- darkpyonix-0.1.0.dist-info/WHEEL +4 -0
- darkpyonix-0.1.0.dist-info/entry_points.txt +5 -0
- darkpyonix-0.1.0.dist-info/licenses/LICENSE +21 -0
darkpyonix/__init__.py
ADDED
|
File without changes
|
darkpyonix/__main__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import socket
|
|
3
|
+
import array
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
import json
|
|
7
|
+
import uuid
|
|
8
|
+
from typing import Dict, List, Optional, AsyncGenerator
|
|
9
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
10
|
+
from fastapi.responses import StreamingResponse
|
|
11
|
+
from contextlib import asynccontextmanager
|
|
12
|
+
#import uvloop # Linux/macOS에서 성능 향상
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class UnixFDManager:
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.unix_sockets: Dict[str, socket.socket] = {}
|
|
18
|
+
|
|
19
|
+
def send_fd(self, sock: socket.socket, fd: int, msg: bytes = b"FD"):
|
|
20
|
+
"""Unix Domain Socket을 통해 FD 전달"""
|
|
21
|
+
try:
|
|
22
|
+
return sock.sendmsg(
|
|
23
|
+
[msg],
|
|
24
|
+
[(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", [fd]))]
|
|
25
|
+
)
|
|
26
|
+
except OSError as e:
|
|
27
|
+
raise RuntimeError(f"Failed to send FD {fd}: {e}")
|
|
28
|
+
|
|
29
|
+
def recv_fd(self, sock: socket.socket, maxfds: int = 1) -> tuple[bytes, List[int]]:
|
|
30
|
+
"""Unix Domain Socket에서 FD 수신"""
|
|
31
|
+
fds = array.array("i")
|
|
32
|
+
msg, ancdata, flags, addr = sock.recvmsg(
|
|
33
|
+
1024,
|
|
34
|
+
socket.CMSG_LEN(maxfds * fds.itemsize)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
received_fds = []
|
|
38
|
+
for cmsg_level, cmsg_type, cmsg_data in ancdata:
|
|
39
|
+
if (cmsg_level == socket.SOL_SOCKET and
|
|
40
|
+
cmsg_type == socket.SCM_RIGHTS):
|
|
41
|
+
fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
|
|
42
|
+
received_fds.extend(fds.tolist())
|
|
43
|
+
|
|
44
|
+
return msg, received_fds
|
|
45
|
+
|
|
46
|
+
# SSE 연결 관리
|
|
47
|
+
class SSEConnection:
|
|
48
|
+
def __init__(self, client_socket: socket.socket, client_addr: tuple):
|
|
49
|
+
self.client_socket = client_socket
|
|
50
|
+
self.client_addr = client_addr
|
|
51
|
+
self.connection_id = str(uuid.uuid4())
|
|
52
|
+
self.is_active = True
|
|
53
|
+
|
|
54
|
+
def close(self):
|
|
55
|
+
"""SSE 연결 종료"""
|
|
56
|
+
self.is_active = False
|
|
57
|
+
if self.client_socket:
|
|
58
|
+
try:
|
|
59
|
+
self.client_socket.close()
|
|
60
|
+
except:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
# 커널 매니저 클래스
|
|
64
|
+
class KernelManager:
|
|
65
|
+
def __init__(self):
|
|
66
|
+
self.kernels: Dict[str, dict] = {} # kernel_id -> kernel_info
|
|
67
|
+
self.sse_connections: Dict[str, SSEConnection] = {}
|
|
68
|
+
self.kernel_sockets: Dict[str, socket.socket] = {}
|
|
69
|
+
|
|
70
|
+
# 플랫폼별 FD 매니저 초기화
|
|
71
|
+
if platform.system() == "Windows":
|
|
72
|
+
self.fd_manager = WindowsFDManager()
|
|
73
|
+
else:
|
|
74
|
+
self.fd_manager = UnixFDManager()
|
|
75
|
+
|
|
76
|
+
async def create_kernel(self, kernel_id: str) -> dict:
|
|
77
|
+
"""새 커널 프로세스 생성"""
|
|
78
|
+
# Unix Domain Socket 쌍 생성 (커널 매니저 <-> 커널)
|
|
79
|
+
if platform.system() != "Windows":
|
|
80
|
+
sock_pair = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
81
|
+
manager_sock, kernel_sock = sock_pair
|
|
82
|
+
|
|
83
|
+
# 커널 프로세스 시작
|
|
84
|
+
kernel_process = await asyncio.create_subprocess_exec(
|
|
85
|
+
"python", "kernel_process.py",
|
|
86
|
+
"--kernel-id", kernel_id,
|
|
87
|
+
"--socket-fd", str(kernel_sock.fileno()),
|
|
88
|
+
pass_fds=[kernel_sock.fileno()] # FD를 자식 프로세스에 전달
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# 소켓 저장
|
|
92
|
+
self.kernel_sockets[kernel_id] = manager_sock
|
|
93
|
+
kernel_sock.close() # 부모에서는 더 이상 필요 없음
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
# Windows Named Pipe 구현
|
|
97
|
+
pipe_name = f"kernel_{kernel_id}"
|
|
98
|
+
# Windows 구현...
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
kernel_info = {
|
|
102
|
+
"process": kernel_process,
|
|
103
|
+
"status": "running",
|
|
104
|
+
"created_at": asyncio.get_event_loop().time()
|
|
105
|
+
}
|
|
106
|
+
self.kernels[kernel_id] = kernel_info
|
|
107
|
+
return kernel_info
|
|
108
|
+
|
|
109
|
+
async def pass_http_socket_to_kernel(self, kernel_id: str, request: Request):
|
|
110
|
+
"""HTTP 연결의 소켓을 커널에 전달"""
|
|
111
|
+
if platform.system() != "Windows":
|
|
112
|
+
# FastAPI/Uvicorn에서 원시 소켓 추출
|
|
113
|
+
transport = request.scope.get("transport")
|
|
114
|
+
if not transport:
|
|
115
|
+
raise ValueError("No transport found in request scope")
|
|
116
|
+
|
|
117
|
+
# Uvicorn transport에서 소켓 추출
|
|
118
|
+
client_socket = transport.get_extra_info('socket')
|
|
119
|
+
if not client_socket:
|
|
120
|
+
raise ValueError("Could not extract socket from transport")
|
|
121
|
+
|
|
122
|
+
kernel_sock = self.kernel_sockets.get(kernel_id)
|
|
123
|
+
if not kernel_sock:
|
|
124
|
+
raise ValueError(f"Kernel {kernel_id} not found")
|
|
125
|
+
|
|
126
|
+
# 클라이언트 소켓 FD를 커널에 전달
|
|
127
|
+
client_fd = client_socket.fileno()
|
|
128
|
+
self.fd_manager.send_fd(kernel_sock, client_fd)
|
|
129
|
+
|
|
130
|
+
# 클라이언트 정보도 함께 전송
|
|
131
|
+
client_info = {
|
|
132
|
+
"connection_type": "sse",
|
|
133
|
+
"client_addr": request.client.host if request.client else "unknown",
|
|
134
|
+
"user_agent": request.headers.get("user-agent", ""),
|
|
135
|
+
"connection_id": str(uuid.uuid4())
|
|
136
|
+
}
|
|
137
|
+
await self._send_json_to_kernel(kernel_sock, client_info)
|
|
138
|
+
|
|
139
|
+
return client_info["connection_id"]
|
|
140
|
+
|
|
141
|
+
else:
|
|
142
|
+
# Windows: DuplicateHandle 구현
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
async def _send_json_to_kernel(self, kernel_sock: socket.socket, data: dict):
|
|
146
|
+
"""커널에 JSON 데이터 전송"""
|
|
147
|
+
message = json.dumps(data).encode() + b'\n'
|
|
148
|
+
kernel_sock.send(message)
|
|
149
|
+
|
|
150
|
+
async def execute_code(self, kernel_id: str, code: str, request: Request) -> AsyncGenerator[str, None]:
|
|
151
|
+
"""코드 실행 요청을 커널에 전달하고 SSE 스트림 생성"""
|
|
152
|
+
# HTTP 소켓을 커널에 전달
|
|
153
|
+
connection_id = await self.pass_http_socket_to_kernel(kernel_id, request)
|
|
154
|
+
|
|
155
|
+
# 실행 요청을 커널에 전송
|
|
156
|
+
execute_request = {
|
|
157
|
+
"msg_type": "execute_request",
|
|
158
|
+
"connection_id": connection_id,
|
|
159
|
+
"content": {
|
|
160
|
+
"code": code,
|
|
161
|
+
"silent": False
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
kernel_sock = self.kernel_sockets.get(kernel_id)
|
|
166
|
+
if kernel_sock:
|
|
167
|
+
await self._send_json_to_kernel(kernel_sock, execute_request)
|
|
168
|
+
|
|
169
|
+
# 이제 커널이 SSE 응답을 직접 클라이언트로 전송
|
|
170
|
+
# 매니저는 연결이 활성화되어 있는지만 확인
|
|
171
|
+
yield f"data: {json.dumps({'status': 'executing', 'connection_id': connection_id})}\n\n"
|
|
172
|
+
|
|
173
|
+
# 커널이 직접 응답을 보내므로 여기서는 연결 상태만 모니터링
|
|
174
|
+
while True:
|
|
175
|
+
await asyncio.sleep(0.1)
|
|
176
|
+
# 실제로는 커널이 직접 SSE 응답을 보냄
|
|
177
|
+
break
|
|
178
|
+
|
|
179
|
+
# FastAPI 애플리케이션
|
|
180
|
+
class JupyterKernelAPI:
|
|
181
|
+
def __init__(self):
|
|
182
|
+
self.app = FastAPI(title="Jupyter Kernel Manager with SSE FD Passing")
|
|
183
|
+
self.kernel_manager = KernelManager()
|
|
184
|
+
self.setup_routes()
|
|
185
|
+
|
|
186
|
+
def setup_routes(self):
|
|
187
|
+
@self.app.post("/kernels")
|
|
188
|
+
async def create_kernel():
|
|
189
|
+
"""새 커널 생성"""
|
|
190
|
+
kernel_id = str(uuid.uuid4())
|
|
191
|
+
kernel_info = await self.kernel_manager.create_kernel(kernel_id)
|
|
192
|
+
return {"kernel_id": kernel_id, "status": kernel_info["status"]}
|
|
193
|
+
|
|
194
|
+
@self.app.get("/kernels")
|
|
195
|
+
async def list_kernels():
|
|
196
|
+
"""커널 목록 조회"""
|
|
197
|
+
return {
|
|
198
|
+
"kernels": [
|
|
199
|
+
{"kernel_id": kid, "status": info["status"]}
|
|
200
|
+
for kid, info in self.kernel_manager.kernels.items()
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@self.app.delete("/kernels/{kernel_id}")
|
|
205
|
+
async def delete_kernel(kernel_id: str):
|
|
206
|
+
"""커널 삭제"""
|
|
207
|
+
if kernel_id not in self.kernel_manager.kernels:
|
|
208
|
+
raise HTTPException(status_code=404, detail="Kernel not found")
|
|
209
|
+
|
|
210
|
+
kernel_info = self.kernel_manager.kernels[kernel_id]
|
|
211
|
+
if kernel_info["process"]:
|
|
212
|
+
kernel_info["process"].terminate()
|
|
213
|
+
await kernel_info["process"].wait()
|
|
214
|
+
|
|
215
|
+
del self.kernel_manager.kernels[kernel_id]
|
|
216
|
+
return {"status": "deleted"}
|
|
217
|
+
|
|
218
|
+
@self.app.post("/kernels/{kernel_id}/execute")
|
|
219
|
+
async def execute_code_endpoint(kernel_id: str, request: Request):
|
|
220
|
+
"""코드 실행 (SSE 응답)"""
|
|
221
|
+
if kernel_id not in self.kernel_manager.kernels:
|
|
222
|
+
raise HTTPException(status_code=404, detail="Kernel not found")
|
|
223
|
+
|
|
224
|
+
# 요청 본문에서 코드 추출
|
|
225
|
+
body = await request.body()
|
|
226
|
+
try:
|
|
227
|
+
data = json.loads(body)
|
|
228
|
+
code = data.get("code", "")
|
|
229
|
+
except json.JSONDecodeError:
|
|
230
|
+
raise HTTPException(status_code=400, detail="Invalid JSON")
|
|
231
|
+
|
|
232
|
+
# SSE 스트림 생성 및 FD 전달
|
|
233
|
+
async def sse_generator():
|
|
234
|
+
async for chunk in self.kernel_manager.execute_code(kernel_id, code, request):
|
|
235
|
+
yield chunk
|
|
236
|
+
|
|
237
|
+
return StreamingResponse(
|
|
238
|
+
sse_generator(),
|
|
239
|
+
media_type="text/event-stream",
|
|
240
|
+
headers={
|
|
241
|
+
"Cache-Control": "no-cache",
|
|
242
|
+
"Connection": "keep-alive",
|
|
243
|
+
"Access-Control-Allow-Origin": "*",
|
|
244
|
+
"Access-Control-Allow-Headers": "Cache-Control"
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# 커널 프로세스 측 코드 (kernel_process.py)
|
|
249
|
+
KERNEL_PROCESS_CODE = '''
|
|
250
|
+
import asyncio
|
|
251
|
+
import socket
|
|
252
|
+
import json
|
|
253
|
+
import sys
|
|
254
|
+
import array
|
|
255
|
+
import time
|
|
256
|
+
import traceback
|
|
257
|
+
|
|
258
|
+
class SSEKernelProcess:
|
|
259
|
+
def __init__(self, kernel_id: str, manager_socket_fd: int):
|
|
260
|
+
self.kernel_id = kernel_id
|
|
261
|
+
# 매니저로부터 받은 소켓 FD 복원
|
|
262
|
+
self.manager_socket = socket.fromfd(
|
|
263
|
+
manager_socket_fd,
|
|
264
|
+
socket.AF_UNIX,
|
|
265
|
+
socket.SOCK_STREAM
|
|
266
|
+
)
|
|
267
|
+
self.client_connections = {}
|
|
268
|
+
|
|
269
|
+
async def run(self):
|
|
270
|
+
"""커널 메인 루프"""
|
|
271
|
+
print(f"Kernel {self.kernel_id} started")
|
|
272
|
+
|
|
273
|
+
while True:
|
|
274
|
+
try:
|
|
275
|
+
# 매니저로부터 클라이언트 FD 수신 대기
|
|
276
|
+
msg, fds = await self.receive_fd_from_manager()
|
|
277
|
+
|
|
278
|
+
if fds:
|
|
279
|
+
# 새 클라이언트 소켓 처리
|
|
280
|
+
for fd in fds:
|
|
281
|
+
client_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
|
|
282
|
+
asyncio.create_task(self.handle_client_sse(client_socket, msg))
|
|
283
|
+
|
|
284
|
+
except Exception as e:
|
|
285
|
+
print(f"Kernel {self.kernel_id} error: {e}")
|
|
286
|
+
traceback.print_exc()
|
|
287
|
+
break
|
|
288
|
+
|
|
289
|
+
async def receive_fd_from_manager(self):
|
|
290
|
+
"""매니저로부터 FD 수신"""
|
|
291
|
+
loop = asyncio.get_event_loop()
|
|
292
|
+
|
|
293
|
+
# 논블로킹으로 메시지 수신
|
|
294
|
+
try:
|
|
295
|
+
ready = await asyncio.wait_for(
|
|
296
|
+
loop.sock_recv(self.manager_socket, 1024),
|
|
297
|
+
timeout=1.0
|
|
298
|
+
)
|
|
299
|
+
except asyncio.TimeoutError:
|
|
300
|
+
return None, []
|
|
301
|
+
|
|
302
|
+
if not ready:
|
|
303
|
+
raise ConnectionError("Manager socket closed")
|
|
304
|
+
|
|
305
|
+
# SCM_RIGHTS로 FD 수신
|
|
306
|
+
fds = array.array("i")
|
|
307
|
+
msg, ancdata, flags, addr = self.manager_socket.recvmsg(
|
|
308
|
+
1024, socket.CMSG_LEN(1 * fds.itemsize)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
received_fds = []
|
|
312
|
+
for cmsg_level, cmsg_type, cmsg_data in ancdata:
|
|
313
|
+
if (cmsg_level == socket.SOL_SOCKET and
|
|
314
|
+
cmsg_type == socket.SCM_RIGHTS):
|
|
315
|
+
fds.frombytes(cmsg_data)
|
|
316
|
+
received_fds.extend(fds.tolist())
|
|
317
|
+
|
|
318
|
+
# JSON 메시지 파싱
|
|
319
|
+
try:
|
|
320
|
+
client_info = json.loads(msg.decode().strip())
|
|
321
|
+
except json.JSONDecodeError:
|
|
322
|
+
client_info = {}
|
|
323
|
+
|
|
324
|
+
return client_info, received_fds
|
|
325
|
+
|
|
326
|
+
async def handle_client_sse(self, client_socket: socket.socket, client_info: dict):
|
|
327
|
+
"""SSE 클라이언트와 직접 통신"""
|
|
328
|
+
connection_id = client_info.get("connection_id", "unknown")
|
|
329
|
+
print(f"Kernel {self.kernel_id} handling SSE client {connection_id} directly")
|
|
330
|
+
|
|
331
|
+
loop = asyncio.get_event_loop()
|
|
332
|
+
|
|
333
|
+
try:
|
|
334
|
+
# HTTP 요청 읽기 (이미 전달된 연결이므로 요청 데이터가 있을 수 있음)
|
|
335
|
+
|
|
336
|
+
# SSE 응답 헤더 전송
|
|
337
|
+
sse_headers = (
|
|
338
|
+
"HTTP/1.1 200 OK\\r\\n"
|
|
339
|
+
"Content-Type: text/event-stream\\r\\n"
|
|
340
|
+
"Cache-Control: no-cache\\r\\n"
|
|
341
|
+
"Connection: keep-alive\\r\\n"
|
|
342
|
+
"Access-Control-Allow-Origin: *\\r\\n"
|
|
343
|
+
"\\r\\n"
|
|
344
|
+
).encode()
|
|
345
|
+
|
|
346
|
+
await loop.sock_sendall(client_socket, sse_headers)
|
|
347
|
+
|
|
348
|
+
# 실행 시작 이벤트
|
|
349
|
+
start_event = f"data: {json.dumps({'status': 'started', 'kernel_id': self.kernel_id})}\\n\\n"
|
|
350
|
+
await loop.sock_sendall(client_socket, start_event.encode())
|
|
351
|
+
|
|
352
|
+
# 실제 코드 실행 시뮬레이션
|
|
353
|
+
await self.execute_python_code(client_socket, client_info)
|
|
354
|
+
|
|
355
|
+
except Exception as e:
|
|
356
|
+
print(f"SSE Client {connection_id} error: {e}")
|
|
357
|
+
traceback.print_exc()
|
|
358
|
+
finally:
|
|
359
|
+
client_socket.close()
|
|
360
|
+
|
|
361
|
+
async def execute_python_code(self, client_socket: socket.socket, client_info: dict):
|
|
362
|
+
"""Python 코드 실행 및 SSE 스트리밍"""
|
|
363
|
+
loop = asyncio.get_event_loop()
|
|
364
|
+
|
|
365
|
+
# 실행 중 이벤트
|
|
366
|
+
executing_event = f"data: {json.dumps({'status': 'executing', 'timestamp': time.time()})}\\n\\n"
|
|
367
|
+
await loop.sock_sendall(client_socket, executing_event.encode())
|
|
368
|
+
|
|
369
|
+
# 코드 실행 시뮬레이션 (실제로는 IPython 커널 로직)
|
|
370
|
+
await asyncio.sleep(0.1) # 실행 지연 시뮬레이션
|
|
371
|
+
|
|
372
|
+
# 결과 스트리밍
|
|
373
|
+
results = [
|
|
374
|
+
{"type": "stdout", "text": "Hello from kernel!"},
|
|
375
|
+
{"type": "execute_result", "data": {"text/plain": "4"}},
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
for result in results:
|
|
379
|
+
result_event = f"data: {json.dumps(result)}\\n\\n"
|
|
380
|
+
await loop.sock_sendall(client_socket, result_event.encode())
|
|
381
|
+
await asyncio.sleep(0.05) # 스트리밍 효과
|
|
382
|
+
|
|
383
|
+
# 완료 이벤트
|
|
384
|
+
complete_event = f"data: {json.dumps({'status': 'complete', 'execution_count': 1})}\\n\\n"
|
|
385
|
+
await loop.sock_sendall(client_socket, complete_event.encode())
|
|
386
|
+
|
|
387
|
+
if __name__ == "__main__":
|
|
388
|
+
import argparse
|
|
389
|
+
parser = argparse.ArgumentParser()
|
|
390
|
+
parser.add_argument("--kernel-id", required=True)
|
|
391
|
+
parser.add_argument("--socket-fd", type=int, required=True)
|
|
392
|
+
args = parser.parse_args()
|
|
393
|
+
|
|
394
|
+
kernel = SSEKernelProcess(args.kernel_id, args.socket_fd)
|
|
395
|
+
asyncio.run(kernel.run())
|
|
396
|
+
'''
|
|
397
|
+
|
|
398
|
+
# 실행을 위한 설정
|
|
399
|
+
def setup_uvloop():
|
|
400
|
+
"""성능 향상을 위한 uvloop 설정 (Linux/macOS)"""
|
|
401
|
+
if platform.system() != "Windows":
|
|
402
|
+
try:
|
|
403
|
+
import uvloop
|
|
404
|
+
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
|
405
|
+
except ImportError:
|
|
406
|
+
print("uvloop not available, using default event loop")
|
|
407
|
+
|
|
408
|
+
async def main():
|
|
409
|
+
"""메인 실행 함수"""
|
|
410
|
+
setup_uvloop()
|
|
411
|
+
|
|
412
|
+
# kernel_process.py 파일 생성
|
|
413
|
+
with open("kernel_process.py", "w") as f:
|
|
414
|
+
f.write(KERNEL_PROCESS_CODE)
|
|
415
|
+
|
|
416
|
+
# FastAPI 앱 실행
|
|
417
|
+
kernel_api = JupyterKernelAPI()
|
|
418
|
+
|
|
419
|
+
import uvicorn
|
|
420
|
+
config = uvicorn.Config(
|
|
421
|
+
kernel_api.app,
|
|
422
|
+
host="0.0.0.0",
|
|
423
|
+
port=8000,
|
|
424
|
+
#loop="uvloop" if platform.system() != "Windows" else "asyncio",
|
|
425
|
+
access_log=False # 성능을 위해 비활성화
|
|
426
|
+
)
|
|
427
|
+
server = uvicorn.Server(config)
|
|
428
|
+
await server.serve()
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
if __name__ == '__main__':
|
|
432
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: darkpyonix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI-optimized Python kernel with VS Code integration
|
|
5
|
+
Author-Email: Your Name <your.email@example.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 DarkPyonix
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.9
|
|
29
|
+
Requires-Dist: fastapi>=0.116.1
|
|
30
|
+
Requires-Dist: uvicorn>=0.35.0
|
|
31
|
+
Provides-Extra: build
|
|
32
|
+
Requires-Dist: pdm>=2.25.5; extra == "build"
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# darkpyonix
|
|
36
|
+
DarkPyonix Kernel for AI/ML Development
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
darkpyonix-0.1.0.dist-info/METADATA,sha256=EZf524iC9dchPenMh6xm_iAaWupMkn8m909fXbqJ8kQ,1677
|
|
2
|
+
darkpyonix-0.1.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
darkpyonix-0.1.0.dist-info/entry_points.txt,sha256=lVTVlrduYQOg2AvQRATpfG1UsMS7GHGLNo6yChSrkRI,72
|
|
4
|
+
darkpyonix-0.1.0.dist-info/licenses/LICENSE,sha256=rptdrmBr1zwKQDp0xJZZVuz6AaLTc1yoxdrDuZrZi1Y,1088
|
|
5
|
+
darkpyonix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
darkpyonix/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
darkpyonix/kernel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
darkpyonix/kernel/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
darkpyonix/manager/app.py,sha256=esyqXlopWKCI7IJUuXrrQrH7hHj0rRYXhva6AFC0HMc,16351
|
|
10
|
+
darkpyonix-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 DarkPyonix
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|