MapleX 2.0.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.
maplex/__init__.py ADDED
@@ -0,0 +1,41 @@
1
+ """
2
+ MapleTree: A Python library for building and managing hierarchical data structures with ease.
3
+ Logger: A simple logging utility for tracking events and debugging.
4
+ """
5
+
6
+ from .mapleColors import ConsoleColors
7
+ from .mapleLogger import Logger
8
+ from .mapleExceptions import (
9
+ InvalidMapleFileFormatException,
10
+ KeyEmptyException,
11
+ MapleDataNotFoundException,
12
+ MapleException,
13
+ MapleFileEmptyException,
14
+ MapleFileLockedException,
15
+ MapleHeaderNotFoundException,
16
+ MapleTagNotFoundException,
17
+ NotAMapleFileException
18
+ )
19
+ from .mapleTreeEditor import MapleTree
20
+ from .utils import winHide, winUnHide
21
+
22
+ __all__ = [
23
+ 'ConsoleColors',
24
+ 'InvalidMapleFileFormatException',
25
+ 'KeyEmptyException',
26
+ 'MapleDataNotFoundException',
27
+ 'MapleException',
28
+ 'MapleFileEmptyException',
29
+ 'MapleFileLockedException',
30
+ 'MapleHeaderNotFoundException',
31
+ 'MapleTagNotFoundException',
32
+ 'NotAMapleFileException',
33
+ 'MapleTree',
34
+ 'Logger',
35
+ 'winHide',
36
+ 'winUnHide'
37
+ ]
38
+
39
+ __version__ = "2.0.0"
40
+ __author__ = "Ryuji Hazama"
41
+ __license__ = "MIT"
maplex/mapleColors.py ADDED
@@ -0,0 +1,46 @@
1
+ from pydantic import BaseModel
2
+
3
+ ##################################
4
+ # Console output colors BaseModel
5
+
6
+ class ConsoleColors(BaseModel):
7
+
8
+ # Standard colors
9
+
10
+ Black: str = "\033[30m"
11
+ Red: str = "\033[31m"
12
+ Green: str = "\033[32m"
13
+ Yellow: str = "\033[33m"
14
+ Blue: str = "\033[34m"
15
+ Magenta: str = "\033[35m"
16
+ LightBlue: str = "\033[36m"
17
+ White: str = "\033[37m"
18
+
19
+ # Background colors
20
+
21
+ bgBlack: str = "\033[40m"
22
+ bgRed: str = "\033[41m"
23
+ bgGreen: str = "\033[42m"
24
+ bgYellow: str = "\033[43m"
25
+ bgBlue: str = "\033[44m"
26
+ bgMagenta: str = "\033[45m"
27
+ bgLightBlue: str = "\033[46m"
28
+ bgWhite: str = "\033[47m"
29
+
30
+ # Bright colors
31
+
32
+ bBlack: str = "\033[90m"
33
+ bRed: str = "\033[91m"
34
+ bGreen: str = "\033[92m"
35
+ bYellow: str = "\033[93m"
36
+ bBlue: str = "\033[94m"
37
+ bMagenta: str = "\033[95m"
38
+ bLightBlue: str = "\033[96m"
39
+ bWhite: str = "\033[97m"
40
+
41
+ # Other formats
42
+
43
+ Bold: str = "\033[1m"
44
+ Underline: str = "\033[4m"
45
+ Reversed: str = "\033[7m"
46
+ Reset: str = "\033[0m"
@@ -0,0 +1,105 @@
1
+ ################################
2
+ # Exception classes
3
+
4
+ class MapleException(Exception):
5
+
6
+ """Basic exception for all exception inside the Maple tree."""
7
+
8
+ class MapleFileNotFoundException(MapleException):
9
+
10
+ def __init__(self, mapleFile: str = "", message: str = "Maple file not found"):
11
+
12
+ self.message = f"{message}: {mapleFile}"
13
+ super().__init__(self.message)
14
+
15
+ class KeyEmptyException(MapleException):
16
+
17
+ def __init__(self, mapleFile: str = "", message: str | None = None):
18
+
19
+ if message is None:
20
+
21
+ self.message = "File encryption toggle was set as \"True\", but the encryption key was not set.\n" \
22
+ "Please set key(bytes) value or encryption toggle to \"False\"."
23
+
24
+ else:
25
+
26
+ self.message = message
27
+
28
+ super().__init__(mapleFile, self.message)
29
+
30
+ class MapleFileLockedException(MapleException):
31
+
32
+ def __init__(self, mapleFile: str = "", message: str = "Maple file has been locked by other instance"):
33
+
34
+ self.message = f"{message}: {mapleFile}"
35
+ super().__init__(self.message)
36
+
37
+ class MapleDataNotFoundException(MapleException):
38
+
39
+ def __init__(self, fileName: str = "", message: str = "Data not found"):
40
+
41
+ self.message = f"{message}: {fileName}"
42
+ super().__init__(self.message)
43
+
44
+ class MapleHeaderNotFoundException(MapleDataNotFoundException):
45
+
46
+ def __init__(self, fileName = "", header: str = "", preHeader: str = "", message = ""):
47
+
48
+ if header != "":
49
+
50
+ self.message = f"Header [{header}] not found"
51
+
52
+ else:
53
+
54
+ self.message = "Header not found"
55
+
56
+ if preHeader != "":
57
+
58
+ self.message = f"{self.message} in [{preHeader}]"
59
+
60
+ if message != "":
61
+
62
+ self.message = message
63
+
64
+ super().__init__(fileName, self.message)
65
+
66
+ class MapleTagNotFoundException(MapleDataNotFoundException):
67
+
68
+ def __init__(self, fileName = "", tag: str = "", header: str = "", message = ""):
69
+
70
+ if tag != "":
71
+
72
+ self.message = f"Tag [{tag}] not found"
73
+
74
+ else:
75
+
76
+ self.message = "Tag not found"
77
+
78
+ if header != "":
79
+
80
+ self.message = f"{self.message} in [{header}]"
81
+
82
+ if message != "":
83
+
84
+ self.message = message
85
+
86
+ super().__init__(self.message, fileName)
87
+
88
+ class NotAMapleFileException(MapleException):
89
+
90
+ def __init__(self, filePath: str = "", message: str = "The file is not a Maple file"):
91
+
92
+ self.message = f"{message}: {filePath}"
93
+ super().__init__(self.message)
94
+
95
+ class InvalidMapleFileFormatException(NotAMapleFileException):
96
+
97
+ def __init__(self, mapleFile = "", message = "Invalid Maple file format"):
98
+
99
+ self.message = f"[{message}: {mapleFile}]"
100
+ super().__init__(self.message)
101
+
102
+ class MapleFileEmptyException(InvalidMapleFileFormatException):
103
+
104
+ def __init__(self, mapleFile="", message="File is empty"):
105
+ super().__init__(mapleFile, message)
maplex/mapleLogger.py ADDED
@@ -0,0 +1,375 @@
1
+ import datetime
2
+ import inspect
3
+ import os
4
+ from os import path, getpid
5
+ import sys
6
+ import traceback
7
+ from enum import IntEnum
8
+ from .mapleTreeEditor import MapleTree
9
+ from .mapleColors import ConsoleColors
10
+
11
+ class Logger:
12
+
13
+ def __init__(self, func: str = "", workingDirectory: str | None = None, cmdLogLevel: str | None = None, fileLogLevel: str | None = None, maxLogSize: float | None = None):
14
+
15
+ """
16
+ Set a negative value to maxLogSize for an infinite log file size.
17
+ """
18
+
19
+ self.intMaxValue = 4294967295
20
+ self.consoleLogLevel = -1
21
+ self.fileLogLevel = -1
22
+ self.func = func
23
+ self.CWD = os.getcwd()
24
+ self.consoleColors = ConsoleColors()
25
+
26
+ # Check the OS (Windows cannot change the console color)
27
+
28
+ systemId = sys.platform
29
+
30
+ if systemId.startswith("win"):
31
+
32
+ self.consoleColors = ConsoleColors(Black="", Red="", Green="", Yellow="", Blue="", Magenta="", LightBlue="", White="",
33
+ bgBlack="", bgRed="", bgGreen="", bgYellow="", bgBlue="", bgMagenta="", bgLightBlue="", bgWhite="",
34
+ bBlack="", bRed="", bGreen="", bYellow="", bBlue="", bMagenta="", bLightBlue="", bWhite="",
35
+ Bold="", Underline="", Reversed="", Reset="")
36
+
37
+ #
38
+ ############################
39
+ # Check config file
40
+
41
+ configFile = path.join(self.CWD, "config.mpl")
42
+
43
+ try:
44
+
45
+ if not path.isfile(configFile):
46
+
47
+ f = open(configFile, "w")
48
+ f.write("MAPLE\n"
49
+ "H *LOG_SETTINGS\n"
50
+ " CMD INFO\n"
51
+ " FLE INFO\n"
52
+ " MAX 3\n"
53
+ " OUT logs\n"
54
+ " CMT TRACE, DEBUG, INFO, WARN, ERROR, FATAL\n"
55
+ "E\nEOF")
56
+ f.close()
57
+
58
+ maple = MapleTree(configFile)
59
+
60
+ except:
61
+
62
+ maple = None
63
+ #
64
+ ############################
65
+ # Check output directory
66
+
67
+ if workingDirectory is not None:
68
+
69
+ self.CWD = workingDirectory
70
+
71
+ elif maple:
72
+
73
+ self.CWD = maple.readMapleTag("OUT", "*LOG_SETTINGS")
74
+
75
+ if self.CWD in {"", None}:
76
+
77
+ self.CWD = path.join(os.getcwd(), "logs")
78
+
79
+ elif not path.isabs(self.CWD):
80
+
81
+ self.CWD = path.join(os.getcwd(), self.CWD)
82
+
83
+ self.logfile = path.join(self.CWD, f"log_{datetime.datetime.now():%Y%m%d}.log")
84
+
85
+ #
86
+ ############################
87
+ # Check log directory
88
+
89
+ if not path.isdir(path.join(self.CWD)):
90
+ os.makedirs(path.join(self.CWD))
91
+
92
+ #
93
+ ############################
94
+ # Set max log file size
95
+
96
+ self.maxLogSize = 0
97
+
98
+ if maxLogSize is not None:
99
+
100
+ self.maxLogSize = maxLogSize * 1000000
101
+
102
+ elif maple is not None:
103
+
104
+ try:
105
+
106
+ logSizeStr = maple.readMapleTag("MAX", "*LOG_SETTINGS")
107
+
108
+ if logSizeStr != "":
109
+
110
+ self.maxLogSize = float(logSizeStr) * 1000000
111
+
112
+ except:
113
+
114
+ pass
115
+
116
+ if self.maxLogSize == 0:
117
+
118
+ self.maxLogSize = 3000000
119
+
120
+ #
121
+ ############################
122
+ # Set output log levels
123
+
124
+ self.consoleLogLevel = -1
125
+ self.fileLogLevel = -1
126
+
127
+ # Console log level
128
+
129
+ if cmdLogLevel is not None:
130
+
131
+ self.consoleLogLevel = self.isLogLevel(cmdLogLevel)
132
+
133
+ if self.consoleLogLevel == -1 and maple is not None:
134
+
135
+ strLogLevel = maple.readMapleTag("CMD", "*LOG_SETTINGS")
136
+
137
+ if strLogLevel is not None:
138
+
139
+ self.consoleLogLevel = self.isLogLevel(strLogLevel)
140
+
141
+ if self.consoleLogLevel == -1:
142
+
143
+ self.consoleLogLevel = self.LogLevel.INFO
144
+
145
+ # File log level
146
+
147
+ if fileLogLevel is not None:
148
+
149
+ self.fileLogLevel = self.isLogLevel(fileLogLevel)
150
+
151
+ if self.fileLogLevel == -1 and maple is not None:
152
+
153
+ strLogLevel = maple.readMapleTag("FLE", "*LOG_SETTINGS")
154
+
155
+ if strLogLevel is not None:
156
+
157
+ self.fileLogLevel = self.isLogLevel(strLogLevel)
158
+
159
+ if self.fileLogLevel == -1:
160
+
161
+ self.fileLogLevel = self.LogLevel.INFO
162
+
163
+ #
164
+ #####################
165
+ # Set log level enum
166
+
167
+ class LogLevel(IntEnum):
168
+
169
+ TRACE = 0
170
+ DEBUG = 1
171
+ INFO = 2
172
+ WARN = 3
173
+ ERROR = 4
174
+ FATAL = 5
175
+
176
+ #
177
+ ################
178
+ # Check log level
179
+
180
+ def isLogLevel(self, lLStr: str) -> LogLevel:
181
+
182
+ for lLevel in self.LogLevel:
183
+ if lLStr == lLevel.name:
184
+ return lLevel
185
+
186
+ return -1
187
+
188
+ #
189
+ #################################
190
+ # Logger
191
+
192
+ def logWriter(self, loglevel: LogLevel, message: any):
193
+
194
+ """
195
+ Output log to log file and console.
196
+ """
197
+
198
+ ''' - - - - - - -*
199
+ * *
200
+ * Logging Object *
201
+ * *
202
+ * - - - - - - -'''
203
+
204
+ # Console colors
205
+
206
+ bBlack = self.consoleColors.bBlack
207
+ Red = self.consoleColors.Red
208
+ bRed = self.consoleColors.bRed
209
+ Green = self.consoleColors.Green
210
+ bLightBlue = self.consoleColors.bLightBlue
211
+ Bold = self.consoleColors.Bold
212
+ Reset = self.consoleColors.Reset
213
+
214
+ f = open(self.logfile, "a")
215
+
216
+ # Get caller informations
217
+
218
+ callerFunc = inspect.stack()[1].function
219
+ callerLine = inspect.stack()[1].lineno
220
+
221
+ try:
222
+
223
+ # Set console color
224
+
225
+ match loglevel:
226
+
227
+ case self.LogLevel.TRACE:
228
+
229
+ col = bBlack
230
+
231
+ case self.LogLevel.DEBUG:
232
+
233
+ col = Green
234
+
235
+ case self.LogLevel.INFO:
236
+
237
+ col = bLightBlue
238
+
239
+ case self.LogLevel.WARN:
240
+
241
+ col = bRed
242
+
243
+ case self.LogLevel.ERROR:
244
+
245
+ col = Red
246
+
247
+ case self.LogLevel.FATAL:
248
+
249
+ col = Bold + Red
250
+
251
+ case _:
252
+
253
+ col = ""
254
+
255
+ # Export to console and log file
256
+
257
+ if loglevel >= self.consoleLogLevel:
258
+ print(f"[{col}{loglevel.name:5}{Reset}]{Green}[{self.func}]{Reset} {bBlack}{callerFunc}({callerLine}){Reset} {message}")
259
+
260
+ if loglevel >= self.fileLogLevel:
261
+ print(f"({getpid()}) {f"{datetime.datetime.now():%F %X.%f}"[:-3]} [{loglevel.name:5}][{self.func}] {callerFunc}({callerLine}) {message}", file=f)
262
+
263
+ except Exception as ex:
264
+
265
+ # If faled to export, print error info to console
266
+
267
+ print(f"{Red}[ERROR] {ex}{Reset}")
268
+
269
+ finally:
270
+ f.close()
271
+
272
+ if self.maxLogSize > 0:
273
+
274
+ # Check file size
275
+
276
+ try:
277
+
278
+ if path.getsize(self.logfile) > self.maxLogSize:
279
+
280
+ i = 0
281
+ logCopyFile = f"{self.logfile}{i}.log"
282
+
283
+ while path.isfile(logCopyFile):
284
+
285
+ i += 1
286
+ logCopyFile = f"{self.logfile}{i}.log"
287
+
288
+ os.rename(self.logfile, logCopyFile)
289
+
290
+ except Exception as ex:
291
+
292
+ print(f"{Red}[ERROR] {ex}{Reset}")
293
+
294
+ #
295
+ ################################
296
+ # Trace
297
+
298
+ def Trace(self, object: any):
299
+
300
+ '''Trace log'''
301
+
302
+ self.logWriter(self.LogLevel.TRACE, object)
303
+
304
+ #
305
+ ################################
306
+ # Debug
307
+
308
+ def Debug(self, object: any):
309
+
310
+ '''Debug log'''
311
+
312
+ self.logWriter(self.LogLevel.DEBUG, object)
313
+
314
+ #
315
+ ################################
316
+ # Info
317
+
318
+ def Info(self, object: any):
319
+
320
+ '''Info log'''
321
+
322
+ self.logWriter(self.LogLevel.INFO, object)
323
+
324
+ #
325
+ ################################
326
+ # Warn
327
+
328
+ def Warn(self, object: any):
329
+
330
+ '''Warn log'''
331
+
332
+ self.logWriter(self.LogLevel.WARN, object)
333
+
334
+ #
335
+ ################################
336
+ # Error
337
+
338
+ def Error(self, object: any):
339
+
340
+ '''Error log'''
341
+
342
+ self.logWriter(self.LogLevel.ERROR, object)
343
+
344
+ #
345
+ ################################
346
+ # Fatal
347
+
348
+ def Fatal(self, object: any):
349
+
350
+ '''Fatal log'''
351
+
352
+ self.logWriter(self.LogLevel.FATAL, object)
353
+
354
+ #
355
+ ################################
356
+ # Error messages
357
+
358
+ def ShowError(self, ex: Exception, message: str | None = None, fatal: bool = False):
359
+
360
+ '''Show and log error'''
361
+
362
+ if fatal:
363
+
364
+ logLevel = self.LogLevel.FATAL
365
+
366
+ else:
367
+
368
+ logLevel = self.LogLevel.ERROR
369
+
370
+ if message is not None:
371
+
372
+ self.logWriter(logLevel, message)
373
+
374
+ self.logWriter(logLevel, ex)
375
+ self.logWriter(logLevel, traceback.format_exc())