CheeseAPI 0.0.1__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.
@@ -0,0 +1,11 @@
1
+ import os, sys
2
+
3
+ sys.path.append(os.path.dirname(os.path.realpath(__file__)))
4
+
5
+ from app import App
6
+ from route import Route
7
+ from response import Response, JsonResponse, RedirectResponse, FileResponse
8
+ from request import Request
9
+ from file import File, MediaFile
10
+ from websocket import websocket
11
+ from cSignal import signal, Signal
@@ -0,0 +1,420 @@
1
+ import os, time, inspect, traceback, multiprocessing
2
+ from typing import Callable, AsyncIterator, Dict, List, Any, Set
3
+ from multiprocessing.process import BaseProcess
4
+
5
+ import uvicorn, CheeseLog, asyncio
6
+ from CheeseLog import logger, Logger
7
+
8
+ import exception
9
+ from route import Route, matchPath
10
+ from request import Request
11
+ from response import Response, BaseResponse, FileResponse
12
+ from file import File
13
+ from websocket import websocket
14
+ from module import LocalModule, Module
15
+ from cSignal import signal
16
+
17
+ class App:
18
+ def __init__(self):
19
+ from system import System
20
+ from workspace import Workspace
21
+ from server import Server
22
+
23
+ self.process: BaseProcess = multiprocessing.current_process()
24
+ self.logger: Logger = logger
25
+
26
+ self.system: System = System()
27
+ self.workspace: Workspace = Workspace()
28
+ self.server: Server = Server(self)
29
+ self.modules: Set[Module] | Set[str] = set()
30
+ self.localModules: Set[LocalModule] | Set[str] | bool = True
31
+
32
+ self.route: Route = Route('')
33
+
34
+ self.server_startingHandles: List[Callable] = []
35
+ self.server_endingHandles: List[Callable] = []
36
+ # http
37
+ self.http_response404Handles: List[Callable] = []
38
+ self.http_response405Handles: List[Callable] = []
39
+ self.http_response500Handles: List[Callable] = []
40
+ self.http_beforeRequestHandles: List[Callable] = []
41
+ self.http_afterResponseHandles: List[Callable] = []
42
+ # websocket
43
+ self.websocket_beforeConnectionHandles: List[Callable] = []
44
+ self.websocket_afterDisconnectHandles: List[Callable] = []
45
+ self.websocket_errorHandles: List[Callable] = []
46
+ self.websocket_notFoundHandles: List[Callable] = []
47
+
48
+ signal.register('server_startingHandle')
49
+ signal.register('server_endingHandle')
50
+ signal.register('http_response404Handle')
51
+ signal.register('http_response405Handle')
52
+ signal.register('http_response500Handle')
53
+ signal.register('http_beforeRequestHandle')
54
+ signal.register('http_afterResponseHandle')
55
+ signal.register('websocket_beforeConnectionHandle')
56
+ signal.register('websocket_afterDisconnectHandle')
57
+ signal.register('websocket_errorHandle')
58
+ signal.register('websocket_notFoundHandle')
59
+
60
+ if self.process.name != 'MainProcess':
61
+ self.init()
62
+
63
+ async def __call__(self, scope, receive, send):
64
+ ''' Server started '''
65
+ if scope['type'] == 'lifespan':
66
+ message = await receive()
67
+ if message['type'] == 'lifespan.startup':
68
+ startTime = time.time() - self.startTimer
69
+ if self.process.name == 'MainProcess':
70
+ CheeseLog.starting('The server started, took {:.6f} seconds'.format(startTime), 'The server started, took \033[34m{:.6f}\033[0m seconds'.format(startTime))
71
+ else:
72
+ CheeseLog.starting(f'The worker {os.getpid()} started, took ' + '{:.6f} seconds'.format(startTime), f'The worker \033[34m{os.getpid()}\033[0m started, took ' + '\033[34m{:.6f}\033[0m seconds'.format(startTime))
73
+
74
+ ''' Http request '''
75
+ if scope['type'] in [ 'http', 'https' ]:
76
+ try:
77
+ timer = time.time()
78
+ body = b''
79
+ bodyFlag = True
80
+ while bodyFlag:
81
+ message = await receive()
82
+ body += message.get('body', b'')
83
+ bodyFlag = message.get('more_body', False)
84
+ request = Request(scope, body)
85
+ response = None
86
+ requestFunc = None
87
+
88
+ # Static
89
+ if self.server.STATIC_PATH and request.path.startswith(self.server.STATIC_PATH):
90
+ try:
91
+ response = FileResponse(File(path = self.workspace.STATIC_PATH + request.path[len(self.server.STATIC_PATH):]))
92
+ except:
93
+ ...
94
+
95
+ if not isinstance(response, FileResponse):
96
+ # 404
97
+ requestFunc, kwargs = matchPath(request.path)
98
+ kwargs['request'] = request
99
+ if not isinstance(requestFunc, dict):
100
+ if signal.receiver('http_response404Handle'):
101
+ await signal.send_async('http_response404Handle', kwargs)
102
+ for http_response404Handle in self.http_response404Handles:
103
+ _response = await self.doFunc(http_response404Handle, kwargs)
104
+ if isinstance(_response, BaseResponse):
105
+ response = _response
106
+ if not isinstance(response, BaseResponse):
107
+ response = Response(status = 404)
108
+
109
+ # 405
110
+ elif request.method not in requestFunc:
111
+ if signal.receiver('http_response405Handle'):
112
+ await signal.send_async('http_response405Handle', kwargs)
113
+ for http_response405Handle in self.http_response405Handles:
114
+ _response = await self.doFunc(http_response405Handle, kwargs)
115
+ if isinstance(_response, BaseResponse):
116
+ response = _response
117
+ if not isinstance(response, BaseResponse):
118
+ response = Response(status = 405)
119
+
120
+ # Other...
121
+ else:
122
+ if signal.receiver('http_beforeRequestHandle'):
123
+ await signal.send_async('http_beforeRequestHandle', kwargs)
124
+ for http_beforeRequestHandle in self.http_beforeRequestHandles:
125
+ _response = await self.doFunc(http_beforeRequestHandle, kwargs)
126
+ if isinstance(_response, BaseResponse):
127
+ response = _response
128
+
129
+ if not isinstance(response, BaseResponse):
130
+ requestFunc = requestFunc[request.method]
131
+ response = await self.doFunc(requestFunc, kwargs)
132
+
133
+ if isinstance(response, BaseResponse):
134
+ if signal.receiver('http_afterResponseHandle'):
135
+ await signal.send_async('http_afterResponseHandle', kwargs)
136
+ for http_afterResponseHandle in self.http_afterResponseHandles:
137
+ kwargs['response'] = response
138
+ _response = await self.doFunc(http_afterResponseHandle, kwargs)
139
+ if isinstance(_response, BaseResponse):
140
+ response = _response
141
+ else:
142
+ CheeseLog.danger(f'The error occured while accessing the {request.method} {request.fullPath}\nTraceback (most recent call last):\n File "{inspect.getsourcefile(requestFunc)}", line {inspect.getsourcelines(requestFunc)[1]}, in <module>\n Function {requestFunc.__name__} needs to return Response, not {response.__class__.__name__}')
143
+ response = Response(status = 500)
144
+ except Exception as e:
145
+ CheeseLog.danger(f'The error occured while accessing the {request.method} {request.fullPath}\n{traceback.format_exc()}'[:-1], f'The error occured while accessing the \033[36m{request.method} {request.fullPath}\033[0m\n{traceback.format_exc()}'[:-1])
146
+ if signal.receiver('http_response500Handle'):
147
+ await signal.send_async('http_response500Handle', kwargs)
148
+ for http_response500Handle in self.http_response500Handles:
149
+ kwargs['exception'] = e
150
+ _response = await self.doFunc(http_response500Handle, kwargs)
151
+ if isinstance(_response, BaseResponse):
152
+ response = _response
153
+ if not isinstance(response, BaseResponse):
154
+ response = Response(status = 500)
155
+
156
+ headers = []
157
+ for key, value in response.headers.items():
158
+ headers.append([key.encode(), value.encode()])
159
+ await send({
160
+ 'type': 'http.response.start',
161
+ 'status': response.status,
162
+ 'headers': headers
163
+ })
164
+
165
+ body = response.body
166
+ if isinstance(response.body, Callable):
167
+ body = response.body()
168
+ if isinstance(body, AsyncIterator):
169
+ try:
170
+ async for value in body:
171
+ if isinstance(body, bytes):
172
+ await send({
173
+ 'type': 'http.response.body',
174
+ 'body': value,
175
+ 'more_body': True
176
+ })
177
+ else:
178
+ await send({
179
+ 'type': 'http.response.body',
180
+ 'body': str(value).encode(),
181
+ 'more_body': True
182
+ })
183
+ except Exception as e:
184
+ await send({
185
+ 'type': 'http.response.body',
186
+ 'body': b''
187
+ })
188
+ else:
189
+ if isinstance(body, bytes):
190
+ await send({
191
+ 'type': 'http.response.body',
192
+ 'body': body
193
+ })
194
+ else:
195
+ await send({
196
+ 'type': 'http.response.body',
197
+ 'body': str(body).encode()
198
+ })
199
+
200
+ diffTime = time.time() - timer
201
+ CheeseLog.http(f'{request.ip} accessed {request.method} {request.fullPath}, returned {response.status}, took ' + '{:.6f}'.format(diffTime) + ' seconds', f'{request.ip} accessed \033[36m{request.method} {request.fullPath}\033[0m, returned \033[34m{response.status}\033[0m, took ' + '\033[34m{:.6f}\033[0m'.format(diffTime) + ' seconds')
202
+
203
+ ''' Websocket '''
204
+ if scope['type'] in [ 'websocket', 'websockets' ]:
205
+ try:
206
+ request = Request(scope)
207
+ requestFunc, kwargs = matchPath(request.path)
208
+ kwargs['request'] = request
209
+ if requestFunc is None or 'WEBSOCKET' not in requestFunc:
210
+ for websocket_notFoundHandle in self.websocket_notFoundHandles:
211
+ await self.doFunc(websocket_notFoundHandle, kwargs)
212
+ return
213
+ requestFunc = requestFunc['WEBSOCKET']
214
+
215
+ if signal.receiver('websocket_beforeConnectionHandle'):
216
+ await signal.send_async('websocket_beforeConnectionHandle', kwargs)
217
+ for websocket_beforeConnectionHandle in self.websocket_beforeConnectionHandles:
218
+ await self.doFunc(websocket_beforeConnectionHandle, kwargs)
219
+
220
+ await send({
221
+ 'type': 'websocket.accept'
222
+ })
223
+
224
+ if (await receive())['type'] == 'websocket.connect':
225
+ CheeseLog.websocket(f'{request.ip} connected {request.path}', f'{request.ip} connected \033[36m{request.path}\033[0m')
226
+
227
+ websocket._CLIENTS[request.sid] = asyncio.Queue()
228
+ async def sendHandle():
229
+ try:
230
+ while True:
231
+ await (await websocket._CLIENTS[request.sid].get())(send)
232
+ except asyncio.CancelledError:
233
+ ...
234
+ task = asyncio.create_task(sendHandle())
235
+
236
+ while True:
237
+ message = await receive()
238
+ if message['type'] == 'websocket.receive':
239
+ if 'text' in message:
240
+ kwargs['value'] = message['text']
241
+ elif 'bytes' in message:
242
+ kwargs['value'] = message['bytes']
243
+ await self.doFunc(requestFunc, kwargs)
244
+ elif message['type'] == 'websocket.disconnect':
245
+ del websocket._CLIENTS[request.sid]
246
+ task.cancel()
247
+ await task
248
+ CheeseLog.websocket(f'{request.ip} disconnected {request.path}', f'{request.ip} disconnected \033[36m{request.path}\033[0m')
249
+ break
250
+
251
+ if signal.receiver('websocket_afterDisconnectHandle'):
252
+ await signal.send_async('websocket_afterDisconnectHandle', kwargs)
253
+ for websocket_afterDisconnectHandle in self.websocket_afterDisconnectHandles:
254
+ await self.doFunc(websocket_afterDisconnectHandle, kwargs)
255
+ except Exception as e:
256
+ CheeseLog.danger(f'The error occured while accessing the WEBSOCKET {request.fullPath}\n{traceback.format_exc()}'[:-1], f'The error occured while accessing the \033[36mWEBSOCKET {request.fullPath}\033[0m\n{traceback.format_exc()}'[:-1])
257
+ for websocket_errorHandle in self.websocket_errorHandles:
258
+ kwargs['exception'] = e
259
+ await self.doFunc(websocket_errorHandle, kwargs)
260
+
261
+ def init(self):
262
+ self.startTimer: float = time.time()
263
+
264
+ _modules = set()
265
+ if self.process.name == 'MainProcess' and len(self.modules):
266
+ CheeseLog.starting(f'Modules:\n{" | ".join(self.modules)}')
267
+ for module in self.modules:
268
+ _modules.add(Module(_modules, module))
269
+ self.modules = _modules
270
+
271
+ if self.localModules is True:
272
+ self.localModules = set()
273
+ for folderName in os.listdir(self.workspace.BASE_PATH):
274
+ if folderName[0] == '.':
275
+ continue
276
+ folderPath = os.path.join(self.workspace.BASE_PATH, folderName)
277
+ if os.path.isdir(folderPath) and folderPath not in [ self.workspace.BASE_PATH + self.workspace.STATIC_PATH[:-1], self.workspace.BASE_PATH + self.workspace.MEDIA_PATH[:-1], self.workspace.BASE_PATH + self.workspace.LOG_PATH[:-1], self.workspace.BASE_PATH + '/__pycache__' ]:
278
+ self.localModules.add(folderName)
279
+ if self.process.name == 'MainProcess' and len(self.localModules):
280
+ CheeseLog.starting(f'Local modules:\n{" | ".join(self.localModules)}')
281
+ _localModules = set()
282
+ for module in self.localModules:
283
+ _localModules.add(LocalModule(self.workspace.BASE_PATH, module))
284
+ self.localModules = _localModules
285
+
286
+ def run(self):
287
+ global app
288
+ app = self
289
+
290
+ CheeseLog.starting(f'Started CheeseAPI master process {os.getpid()}', f'Started CheeseAPI master process \033[34m{os.getpid()}\033[0m')
291
+ CheeseLog.starting('The application starts loading...')
292
+
293
+ CheeseLog.starting('''System information:
294
+ system: ''' + {
295
+ 'WINDOWS': 'Windows',
296
+ 'LINUX': 'Linux',
297
+ 'MACOS': 'MacOS',
298
+ 'OTHER': 'Other'
299
+ }[self.system.SYSTEM.value] + f'''
300
+ python version: {self.system.PYTHON_VERSION}''' + (f'''
301
+ CheeseAPI version: {self.system.CHEESEAPI_VERSION}''' if self.system.CHEESEAPI_VERSION is not None else ''))
302
+
303
+ CheeseLog.starting(f'''Workspace information:
304
+ CheeseAPI path: {self.workspace.CHEESEAPI_PATH}
305
+ base path: {self.workspace.BASE_PATH}''' + (f'''
306
+ static path: .{self.workspace.STATIC_PATH}''' if self.server.STATIC_PATH is not False else '') + f'''
307
+ media path: .{self.workspace.MEDIA_PATH}''' + (f'''
308
+ log path: .{self.workspace.LOG_PATH}''' if self.server.LOG_FILENAME is not False else ''), f'''Workspace information:
309
+ CheeseAPI path: \033[4;36m{self.workspace.CHEESEAPI_PATH}\033[0m
310
+ base path: \033[4;36m{self.workspace.BASE_PATH}\033[0m''' + (f'''
311
+ static path: \033[4;36m.{self.workspace.STATIC_PATH}\033[0m''' if self.server.STATIC_PATH is not False else '') + f'''
312
+ media path: \033[4;36m.{self.workspace.MEDIA_PATH}\033[0m''' + (f'''
313
+ log path: \033[4;36m.{self.workspace.LOG_PATH}\033[0m''' if self.server.LOG_FILENAME is not False else ''))
314
+
315
+ CheeseLog.starting(f'''Server information:
316
+ host: {self.server.HOST}
317
+ port: {self.server.PORT}
318
+ workers: {self.server.WORKERS}
319
+ is reload: {self.server.IS_RELOAD}
320
+ is debug: {self.server.IS_DEBUG}
321
+ is request logged: {self.server.IS_REQUEST_LOGGED}''' + (f'''
322
+ static path: {self.server.STATIC_PATH}''' if self.server.STATIC_PATH is not False else '') + (f'''
323
+ current log file path: .{logger.filePath[len(self.workspace.BASE_PATH):]}''' if self.server.LOG_FILENAME is not False else ''), f'''Server information:
324
+ host: \033[36m{self.server.HOST}\033[0m
325
+ port: \033[34m{self.server.PORT}\033[0m
326
+ workers: \033[34m{self.server.WORKERS}\033[0m
327
+ is reload: \033[34m{self.server.IS_RELOAD}\033[0m
328
+ is debug: \033[34m{self.server.IS_DEBUG}\033[0m
329
+ is request logged: \033[34m{self.server.IS_REQUEST_LOGGED}\033[0m''' + (f'''
330
+ static path: \033[34m{self.server.STATIC_PATH}\033[0m''' if self.server.STATIC_PATH is not False else '') + (f'''
331
+ current log file path: \033[4;36m.{logger.filePath[len(self.workspace.BASE_PATH):]}\033[0m''' if self.server.LOG_FILENAME is not False else ''))
332
+
333
+ self.init()
334
+
335
+ CheeseLog.starting(f'The server running on http://{self.server.HOST}:{self.server.PORT}', f'The server running on \033[4;36mhttp://{self.server.HOST}:{self.server.PORT}\033[0m')
336
+
337
+ if signal.receiver('server_startingHandle'):
338
+ signal.send('server_startingHandle')
339
+ for server_startingHandle in self.server_startingHandles:
340
+ server_startingHandle()
341
+
342
+ uvicorn.run(
343
+ 'app:app',
344
+ host = self.server.HOST,
345
+ port = self.server.PORT,
346
+ reload = self.server.IS_RELOAD,
347
+ workers = self.server.WORKERS,
348
+ log_level = 'critical'
349
+ )
350
+
351
+ if signal.receiver('server_endingHandle'):
352
+ signal.send('server_endingHandle')
353
+ for server_endingHandle in self.server_endingHandles:
354
+ server_endingHandle()
355
+
356
+ print('')
357
+ CheeseLog.ending('The application tries to stop...')
358
+ runningTime = time.time() - self.startTimer
359
+ endingMessage = 'The application stopped, running '
360
+ endingColorfulMessage = 'The application stopped, running '
361
+ days = int(runningTime // 86400)
362
+ if days:
363
+ endingMessage += f'{days} days '
364
+ endingColorfulMessage += f'\033[34m{days}\033[0m days '
365
+ hours = int(runningTime % 24 // 3600)
366
+ if days or hours:
367
+ endingMessage += f'{hours} hours '
368
+ endingColorfulMessage += f'\033[34m{hours}\033[0m hours '
369
+ minutes = int(runningTime % 3600 // 60)
370
+ if days or hours or minutes:
371
+ endingMessage += f'{minutes} minutes '
372
+ endingColorfulMessage += f'\033[34m{minutes}\033[0m minutes '
373
+ endingMessage += '{:.6f} seconds'.format(runningTime % 60)
374
+ endingColorfulMessage += '\033[34m{:.6f}\033[0m seconds'.format(runningTime % 60)
375
+ CheeseLog.ending(endingMessage, endingColorfulMessage)
376
+ if self.logger.is_alive():
377
+ self.logger.stop()
378
+
379
+ async def doFunc(self, func: Callable, kwargs: Dict[str, Any] = {}):
380
+ _kwargs = {}
381
+ sig = inspect.signature(func)
382
+ for key, value in kwargs.items():
383
+ if key in sig.parameters or 'kwargs' in sig.parameters:
384
+ _kwargs[key] = value
385
+ if inspect.iscoroutinefunction(func):
386
+ return await func(**_kwargs)
387
+ else:
388
+ return func(**_kwargs)
389
+
390
+ def server_startingHandle(self, func: Callable):
391
+ self.server_startingHandles.append(func)
392
+
393
+ def server_endingHandle(self, func: Callable):
394
+ self.server_endingHandles.append(func)
395
+
396
+ def http_response404Handle(self, func: Callable):
397
+ self.http_response404Handles.append(func)
398
+
399
+ def http_response405Handle(self, func: Callable):
400
+ self.http_response405Handles.append(func)
401
+
402
+ def http_response500Handle(self, func: Callable):
403
+ self.http_response500Handles.append(func)
404
+
405
+ def http_beforeRequestHandle(self, func: Callable):
406
+ self.http_beforeRequestHandles.append(func)
407
+
408
+ def http_afterResponseHandle(self, func: Callable):
409
+ self.http_afterResponseHandles.append(func)
410
+
411
+ def websocket_beforeConnectionHandle(self, func: Callable):
412
+ self.websocket_beforeConnectionHandles.append(func)
413
+
414
+ def websocket_afterDisconnectHandle(self, func: Callable):
415
+ self.websocket_afterDisconnectHandles.append(func)
416
+
417
+ def websocket_errorHandle(self, func: Callable):
418
+ self.websocket_errorHandles.append(func)
419
+
420
+ app: App | None = None
@@ -0,0 +1,38 @@
1
+ from typing import Dict
2
+
3
+ import blinker
4
+
5
+ class Signal:
6
+ def __init__(self):
7
+ self._values: Dict[str, blinker.NamedSignal] = {}
8
+
9
+ def register(self, name: str):
10
+ if name in self._values:
11
+ raise KeyError('this name has been registered')
12
+
13
+ self._values[name] = blinker.signal(name)
14
+
15
+ def connect(self, name: str):
16
+ if name not in self._values:
17
+ raise KeyError('no signal with this name')
18
+
19
+ def decorator(func):
20
+ self._values[name].connect(func, weak = False)
21
+ return decorator
22
+
23
+ def receiver(self, name: str):
24
+ if name not in self._values:
25
+ raise KeyError('no signal with this name')
26
+ return self._values[name].receivers
27
+
28
+ def send(self, name: str, *args, **kwargs):
29
+ if name not in self._values:
30
+ raise KeyError('no signal with this name')
31
+ self._values[name].send(*args, **kwargs)
32
+
33
+ async def send_async(self, name: str, *args, **kwargs):
34
+ if name not in self._values:
35
+ raise KeyError('no signal with this name')
36
+ await self._values[name].send_async(*args, **kwargs)
37
+
38
+ signal = Signal()
@@ -0,0 +1,17 @@
1
+ import sys, traceback, threading
2
+
3
+ from CheeseLog import error, danger
4
+
5
+ def sysException(*args, **kwargs):
6
+ try:
7
+ raise args[1]
8
+ except:
9
+ error(f'The error occured while the program running:\n{traceback.format_exc()}'[:-1])
10
+ sys.excepthook = sysException
11
+
12
+ def threadException(*args, **kwargs):
13
+ try:
14
+ raise args[0][1]
15
+ except:
16
+ danger(f'The error occured while the program running:\n{traceback.format_exc()}'[:-1])
17
+ threading.excepthook = threadException
@@ -0,0 +1,66 @@
1
+ import os
2
+ from typing import overload
3
+
4
+ import CheeseLog
5
+
6
+ class File:
7
+ @overload
8
+ def __init__(self, path: str):
9
+ ...
10
+
11
+ @overload
12
+ def __init__(self, name: str, data: bytes):
13
+ ...
14
+
15
+ def __init__(self, name: str | None = None, data: bytes | None = None, path: str | None = None):
16
+ from app import app
17
+
18
+ self.name: str | None = name
19
+ self.data: bytes | None = data
20
+ self.path: str | None = path
21
+
22
+ if path:
23
+ self.filePath = path
24
+ if not os.path.exists(app.workspace.BASE_PATH + self.filePath):
25
+ raise FileNotFoundError(f'no file with this path: \'{self.filePath}\'')
26
+ if os.path.isdir(app.workspace.BASE_PATH + self.filePath):
27
+ raise IsADirectoryError(f'the file is a directory: \'{self.filePath}\'')
28
+ self.name = self.filePath.split('/')[-1]
29
+ with open(app.workspace.BASE_PATH + self.filePath, 'rb') as f:
30
+ self.data = f.read()
31
+
32
+ def save(self, path: str | None = None):
33
+ from app import app
34
+
35
+ if path:
36
+ if path[-1] == '/':
37
+ self.path = path + self.name
38
+ filepath = app.workspace.BASE_PATH + self.path
39
+ else:
40
+ self.path = path
41
+ self.name = path.split('/')[-1]
42
+ filepath = app.workspace.BASE_PATH + self.path
43
+ os.makedirs(os.path.dirname(filepath), exist_ok = True)
44
+ if os.path.exists(filepath):
45
+ CheeseLog.warning(f'the file will be covered: {self.path}', f'the file will be covered: \033[36m{self.path}\033[0m')
46
+ with open(filepath, 'w') as f:
47
+ f.write(self.data)
48
+ else:
49
+ if not self.path:
50
+ raise ValueError('could not get the file path')
51
+ os.makedirs(os.path.dirname(app.workspace.BASE_PATH + self.path), exist_ok = True)
52
+ if os.path.exists(filepath):
53
+ CheeseLog.warning(f'the file will be covered: {self.path}', f'the file will be covered: \033[36m{self.path}\033[0m')
54
+ with open(filepath, 'wb') as f:
55
+ f.write(self.data)
56
+
57
+ def saveMedia(self, path: str):
58
+ from app import app
59
+
60
+ self.save(app.workspace.MEDIA_PATH + path)
61
+
62
+ class MediaFile(File):
63
+ def __init__(self, path: str):
64
+ from app import app
65
+
66
+ super().__init__(None, None, app.workspace.MEDIA_PATH + path)
@@ -0,0 +1,59 @@
1
+ import os, traceback, inspect, pkg_resources
2
+ from typing import Set
3
+
4
+ import CheeseLog
5
+
6
+ class Module:
7
+ def __init__(self, modules, name: str):
8
+ self.name: str = name
9
+ self.subModules: Set[str] = set()
10
+
11
+ try:
12
+ mainModule = __import__(name)
13
+ self.version: str = pkg_resources.get_distribution(self.name).version
14
+ except:
15
+ CheeseLog.error(f'The error occured while the module \'{name}\' loading\n{traceback.format_exc()}'[:-1])
16
+ raise SystemExit()
17
+
18
+ dependencies = None
19
+ try:
20
+ dependencies = mainModule.CheeseAPI_module_dependencies
21
+ except:
22
+ ...
23
+ if dependencies:
24
+ for dependency in dependencies:
25
+ if modules not in modules:
26
+ modules.add(Module(modules, dependency))
27
+
28
+ modulePath = os.path.dirname(inspect.getfile(mainModule))
29
+ for filename in os.listdir(modulePath):
30
+ filePath = os.path.join(modulePath, filename)
31
+ if os.path.isfile(filePath) and filename != '__init__.py':
32
+ filename = filename[:-3]
33
+ try:
34
+ module = __import__(f'{self.name}.{filename}')
35
+ except:
36
+ CheeseLog.error(f'The error occured while the module \'{name}\' loading\n{traceback.format_exc()}'[:-1])
37
+ raise SystemExit()
38
+
39
+ self.subModules.add(module)
40
+
41
+ class LocalModule:
42
+ def __init__(self, basePath: str, name: str):
43
+ self.name: str = name
44
+ self.subModules: Set[str] = set()
45
+
46
+ modulePath = os.path.join(basePath, name)
47
+ if not os.path.isdir(modulePath):
48
+ raise ImportError(f'could not find module \'{name}\'')
49
+
50
+ for filename in os.listdir(modulePath):
51
+ filePath = os.path.join(modulePath, filename)
52
+ if os.path.isfile(filePath) and filename != '__init__.py':
53
+ filename = filename[:-3]
54
+ try:
55
+ module = __import__(f'{self.name}.{filename}')
56
+ except:
57
+ CheeseLog.error(f'The error occured while the local module \'{name}\' loading\n{traceback.format_exc()}'[:-1])
58
+ raise SystemExit()
59
+ self.subModules.add(module)