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.
@@ -0,0 +1,757 @@
1
+ import os.path as path
2
+ from cryptography.fernet import Fernet
3
+ from . import mapleExceptions as mExc
4
+
5
+ class MapleTree:
6
+
7
+ def __init__(self, fileName: str, tabInd: int = 4, encrypt: bool = False, key: bytes | None = None, createBaseFile: bool = False):
8
+
9
+ """
10
+ key must be base_64 bytes.
11
+ """
12
+
13
+ self.TAB_FORMAT = " " * tabInd
14
+ self.ENCRYPT = encrypt
15
+ self.KEY = key
16
+ self.fileName = fileName
17
+
18
+ if encrypt and key is None:
19
+
20
+ raise mExc.KeyEmptyException(fileName)
21
+
22
+ f = None
23
+
24
+ if createBaseFile and not path.isfile(fileName):
25
+
26
+ # Create a base Maple file
27
+
28
+ try:
29
+
30
+ mapleBaseString = "MAPLE\nEOF"
31
+
32
+ if encrypt:
33
+
34
+ # Encrypt data
35
+
36
+ mapleBaseString = Fernet(key).encrypt(mapleBaseString.encode()).decode()
37
+
38
+ f = open(fileName, "w")
39
+ f.write(mapleBaseString)
40
+ f.close()
41
+
42
+ except Exception as e:
43
+
44
+ raise mExc.MapleException(e) from e
45
+
46
+ finally:
47
+
48
+ if f is not None:
49
+ f.close()
50
+
51
+ try:
52
+
53
+ f = open(fileName, "r")
54
+
55
+ if encrypt:
56
+
57
+ # Decode encryption
58
+
59
+ fileData = f.read()
60
+ fileData = Fernet(key).decrypt(fileData.encode()).decode()
61
+ self.fileStream = fileData.split("\n")
62
+
63
+ # Add \r at the end of each line
64
+
65
+ for i, fileLine in enumerate(self.fileStream):
66
+
67
+ self.fileStream[i] = f"{fileLine}\n"
68
+
69
+ else:
70
+
71
+ self.fileStream = f.readlines()
72
+
73
+ # If the file is only one line or empty
74
+
75
+ if len(self.fileStream) < 2:
76
+
77
+ raise mExc.MapleFileEmptyException(fileName)
78
+
79
+ # Search data region
80
+
81
+ self.mapleIndex = self.fileStream.index("MAPLE\n")
82
+ self.eofIndex = self._findEof(self.mapleIndex)
83
+
84
+ # Check data format
85
+
86
+ self._mapleFormatter()
87
+
88
+ except mExc.MapleFileEmptyException:
89
+
90
+ raise
91
+
92
+ except FileNotFoundError as fnfe:
93
+
94
+ raise mExc.MapleFileNotFoundException(fileName) from fnfe
95
+
96
+ except ValueError or mExc.InvalidMapleFileFormatException as ve:
97
+
98
+ raise mExc.InvalidMapleFileFormatException(fileName) from ve
99
+ except Exception as ex:
100
+
101
+ raise mExc.MapleException(ex) from ex
102
+
103
+ finally:
104
+
105
+ if f is not None:
106
+ f.close()
107
+
108
+ #
109
+ ##############################
110
+ # Lock file instance
111
+
112
+ #
113
+ ##############################
114
+ # Unlock file instance
115
+
116
+ #
117
+ ##############################
118
+ # Read file
119
+
120
+ #
121
+ ##############################
122
+ # Encrypt data
123
+
124
+ def __encryptData(self) -> str:
125
+
126
+ """
127
+ Return encrypted base_64 string
128
+ """
129
+
130
+ fileData = "".join(self.fileStream).encode()
131
+ fileData = Fernet(self.KEY).encrypt(fileData).decode()
132
+
133
+ return fileData
134
+
135
+ #
136
+ ##############################
137
+ # Save to file
138
+
139
+ def _saveToFile(self):
140
+
141
+ f = None
142
+
143
+ # Create file data
144
+
145
+ try:
146
+
147
+ if self.ENCRYPT:
148
+
149
+ fileData = self.__encryptData()
150
+
151
+ else:
152
+
153
+ fileData = "".join(self.fileStream)
154
+
155
+ f = open(self.fileName, "w")
156
+ f.writelines(fileData)
157
+ f.close()
158
+
159
+ except Exception as e:
160
+
161
+ raise mExc.MapleException(e) from e
162
+
163
+ finally:
164
+
165
+ if f is not None:
166
+ f.close()
167
+
168
+ #
169
+ ##############################
170
+ # Remove white space
171
+
172
+ def __removeWhiteSpace(self, strLine: str) -> str:
173
+
174
+ strLen = len(strLine)
175
+ ind = 0
176
+
177
+ while ind < strLen:
178
+
179
+ if strLine[ind] != " " and strLine[ind] != "\t":
180
+ break
181
+
182
+ ind += 1
183
+
184
+ return strLine[ind:strLen]
185
+
186
+ #
187
+ ################################
188
+ # Get tag
189
+
190
+ def __getTag(self, mapleLine: str) -> str:
191
+
192
+ """Get a tag from a data line."""
193
+
194
+ if mapleLine == "":
195
+ return ""
196
+
197
+ # Remove white space in front and add return at the end
198
+
199
+ mapleLine = f"{self.__removeWhiteSpace(mapleLine)}\n"
200
+ strLen = len(mapleLine)
201
+
202
+ # Start read tag
203
+
204
+ try:
205
+
206
+ for ind in range(0, strLen):
207
+
208
+ if mapleLine[ind] == " " or mapleLine[ind] == "\n" or mapleLine[ind] == "\r":
209
+ break
210
+
211
+ except Exception as ex:
212
+
213
+ raise mExc.MapleException from ex
214
+
215
+ return mapleLine[:ind]
216
+
217
+ #
218
+ ###########################
219
+ # Get value
220
+
221
+ def __getValue(self, mapleLine: str) -> str:
222
+
223
+ """Get a value from a data line."""
224
+
225
+ ind = 0
226
+
227
+ # Remove white space in front
228
+
229
+ mapleLine = self.__removeWhiteSpace(mapleLine)
230
+ strLen = len(mapleLine)
231
+
232
+ if strLen < 2 or mapleLine == "":
233
+ return ""
234
+
235
+ # Remove tag
236
+
237
+ try:
238
+ for ind in range(0, strLen):
239
+
240
+ if mapleLine[ind] == " " or mapleLine[ind] == "\n" or mapleLine[ind] == "\r":
241
+ ind += 1
242
+ break
243
+
244
+ except Exception as ex:
245
+
246
+ raise mExc.MapleException from ex
247
+
248
+ # Return value
249
+
250
+ if ind >= strLen - 1:
251
+
252
+ return ""
253
+
254
+ else:
255
+
256
+ return mapleLine[ind:strLen - 1]
257
+
258
+ #
259
+ ####################################
260
+ # Header not found exception handler
261
+
262
+ def __headerNotFoundExceptionHandler(self, headInd: int, *headers: str) -> None:
263
+
264
+ if headInd < 1:
265
+
266
+ raise mExc.MapleHeaderNotFoundException(self.fileName, headers[headInd])
267
+
268
+ else:
269
+
270
+ raise mExc.MapleHeaderNotFoundException(self.fileName, headers[headInd], headers[headInd - 1])
271
+ #
272
+ #################################
273
+ # Find EOF
274
+
275
+ def _findEof(self, startInd: int) -> int:
276
+
277
+ """"Find EOF line index"""
278
+
279
+ listLen = len(self.fileStream)
280
+
281
+ while startInd < listLen:
282
+
283
+ startInd += 1
284
+
285
+ if self.__getTag(self.fileStream[startInd]) == "EOF":
286
+
287
+ return startInd
288
+
289
+ raise mExc.InvalidMapleFileFormatException(self.fileName)
290
+
291
+ #
292
+ #################################
293
+ # ToE
294
+
295
+ def __ToE(self, curInd: int) -> int:
296
+
297
+ """Return E tag line index of current level
298
+ Raise"""
299
+
300
+ while curInd < self.eofIndex:
301
+
302
+ curInd += 1
303
+ mapleTag = self.__getTag(self.fileStream[curInd])
304
+
305
+ if mapleTag == "E":
306
+
307
+ return curInd
308
+
309
+ elif mapleTag == "H":
310
+
311
+ curInd = self.__ToE(curInd)
312
+
313
+ raise mExc.InvalidMapleFileFormatException(self.fileName)
314
+
315
+ #
316
+ ######################
317
+ # Format maple file
318
+
319
+ def _mapleFormatter(self, willSave: bool = False):
320
+
321
+ """Format Maple stream
322
+ and save to file if willSave is True"""
323
+
324
+ try:
325
+
326
+ ind = 0
327
+
328
+ # Format
329
+
330
+ for i, mapleLine in enumerate(self.fileStream, self.mapleIndex):
331
+
332
+ mapleLine = self.__removeWhiteSpace(mapleLine)
333
+ tag = self.__getTag(mapleLine)
334
+
335
+ if tag == "EOF":
336
+
337
+ if ind != 0:
338
+
339
+ raise mExc.InvalidMapleFileFormatException(self.fileName, "EOF tag in the middle of the data")
340
+
341
+ break
342
+
343
+ elif tag == "E":
344
+
345
+ ind -= 1
346
+
347
+ if ind < 0:
348
+
349
+ raise mExc.InvalidMapleFileFormatException(self.fileName)
350
+
351
+ self.fileStream[i] = f"{self.TAB_FORMAT * ind}{mapleLine}"
352
+
353
+ if tag == "H":
354
+
355
+ ind += 1
356
+
357
+ except mExc.InvalidMapleFileFormatException:
358
+
359
+ raise
360
+
361
+ except Exception as ex:
362
+
363
+ raise mExc.MapleException(ex) from ex
364
+
365
+ # Save to file
366
+
367
+ if willSave:
368
+
369
+ self._saveToFile()
370
+
371
+ #
372
+ #################################
373
+ # Find header
374
+
375
+ def _findHeader(self, headers: list):
376
+
377
+ """Serch header index.\n
378
+ If the headers exist, return True, last header line index.\n
379
+ If the headers does not exist, return False, E line index, last found headers index."""
380
+
381
+ headCount = len(headers)
382
+ ind = 0
383
+ headInd = self.mapleIndex
384
+ eInd = self.eofIndex
385
+
386
+ # Find header
387
+
388
+ try:
389
+
390
+ while ind < headCount:
391
+
392
+ header = f"{self.TAB_FORMAT * ind}H {headers[ind]}\n"
393
+ headInd = self.fileStream.index(header, headInd, eInd)
394
+ eInd = self.__ToE(headInd)
395
+
396
+ ind += 1
397
+
398
+ return True, eInd, headInd
399
+
400
+ except ValueError:
401
+
402
+ return False, eInd, ind
403
+
404
+ except mExc.InvalidMapleFileFormatException:
405
+
406
+ raise
407
+
408
+ except Exception as e:
409
+
410
+ raise mExc.MapleException(e) from e
411
+
412
+ #
413
+ #################################
414
+ # Find tag line
415
+
416
+ def _findTagLine(self, tag: str, headInd: int, eInd: int) -> int:
417
+
418
+ while headInd < eInd:
419
+
420
+ headInd += 1
421
+ tagLine = self.__getTag(self.fileStream[headInd])
422
+
423
+ if tagLine == "H":
424
+
425
+ headInd = self.__ToE(headInd)
426
+
427
+ elif tagLine == tag:
428
+
429
+ return headInd
430
+
431
+ raise mExc.MapleTagNotFoundException(self.fileName, tag)
432
+
433
+ #
434
+ #################################
435
+ # Read tag line
436
+
437
+ def readMapleTag(self, tag: str, *headers: str) -> str:
438
+
439
+ '''
440
+ Read a Maple file tag line value in headers
441
+ '''
442
+
443
+ headInd = self.mapleIndex
444
+ eInd = self.eofIndex
445
+
446
+ # Serch headers
447
+
448
+ isFound, eInd, headInd = self._findHeader(headers)
449
+
450
+ if not isFound:
451
+
452
+ self.__headerNotFoundExceptionHandler(headInd, headers)
453
+
454
+ # Find tag
455
+
456
+ try:
457
+
458
+ ind = self._findTagLine(tag, headInd, eInd)
459
+ return self.__getValue(self.fileStream[ind])
460
+
461
+ except mExc.MapleTagNotFoundException:
462
+
463
+ return None
464
+
465
+ except Exception as e:
466
+
467
+ raise mExc.MapleException(e) from e
468
+
469
+ #
470
+ ###################################################
471
+ # Save tag line
472
+
473
+ def saveTagLine(self, tag: str, valueStr: str, willSave: bool, *headers: str) -> None:
474
+
475
+ """Save valueStr to tag in headers.\n
476
+ If the headers does not exist, create new headers.\n
477
+ Overwrte file if sillSave == True"""
478
+
479
+ # Find headers
480
+
481
+ isHead, eInd, headInd = self._findHeader(headers)
482
+
483
+ if not isHead:
484
+
485
+ # Create new headers
486
+
487
+ headLen = len(headers)
488
+
489
+ while headInd < headLen:
490
+
491
+ self.fileStream.insert(eInd, f"H {headers[headInd]}\n")
492
+ eInd += 1
493
+ self.fileStream.insert(eInd, "E\n")
494
+ headInd += 1
495
+
496
+ tagInd = eInd
497
+
498
+ else:
499
+
500
+ # Find tag
501
+
502
+ try:
503
+
504
+ tagInd = self._findTagLine(tag, headInd, eInd)
505
+
506
+ except mExc.MapleTagNotFoundException:
507
+
508
+ # If the tag does not exist
509
+
510
+ tagInd = eInd
511
+
512
+ except Exception as e:
513
+
514
+ raise mExc.MapleException(e) from e
515
+
516
+ # Save tag line
517
+
518
+ if tagInd == eInd:
519
+
520
+ # If it is a new line
521
+
522
+ self.fileStream.insert(tagInd, f"{tag} {valueStr}\n")
523
+
524
+ else:
525
+
526
+ # Overwite
527
+
528
+ self.fileStream[tagInd] = f"{tag} {valueStr}\n"
529
+
530
+ # Save?
531
+
532
+ self._mapleFormatter(willSave)
533
+
534
+ # Refresh EOF index
535
+
536
+ self.eofIndex = self._findEof(self.eofIndex - 1)
537
+
538
+ #
539
+ #############################
540
+ # Delete tag line
541
+
542
+ def deleteTag(self, delTag: str, willSave: bool = False, *headers: str) -> bool:
543
+
544
+ """
545
+ Delete tag(delTag) from header(headers) in Maple file(delFile)\n
546
+ Return True if it success.
547
+ """
548
+
549
+ try:
550
+
551
+ gotHeader, eInd, headInd = self._findHeader(headers)
552
+
553
+ if not gotHeader:
554
+
555
+ self.__headerNotFoundExceptionHandler(headInd, headers)
556
+
557
+ tagInd = self._findTagLine(delTag, headInd, eInd)
558
+ self.fileStream.pop(tagInd)
559
+
560
+ # Save?
561
+
562
+ if willSave:
563
+
564
+ self._saveToFile()
565
+
566
+ # Refresh EOF index
567
+
568
+ self.eofIndex = self._findEof(tagInd)
569
+
570
+ except mExc.MapleDataNotFoundException as dnfe:
571
+
572
+ raise mExc.MapleDataNotFoundException(self.fileName) from dnfe
573
+
574
+ except Exception as ex:
575
+
576
+ raise mExc.MapleException(ex) from ex
577
+
578
+ return True
579
+ #
580
+ ############################
581
+ # Get tag value dictioanry
582
+
583
+ def getTagValueDic(self, *headers: str) -> dict[str, str]:
584
+
585
+ """Get and return tag:value dictionary from headers in Maple file"""
586
+
587
+ retDic = {}
588
+
589
+ try:
590
+
591
+ # Find header
592
+
593
+ gotHeader, eInd, headInd = self._findHeader(headers)
594
+
595
+ if not gotHeader:
596
+
597
+ self.__headerNotFoundExceptionHandler(headInd, headers)
598
+
599
+ # Get tag and values
600
+
601
+ while headInd < eInd - 1:
602
+
603
+ headInd += 1
604
+ lineTag = self.__getTag(self.fileStream[headInd])
605
+
606
+ if lineTag == "H":
607
+
608
+ headInd = self.__ToE(headInd)
609
+
610
+ else:
611
+
612
+ retDic[lineTag] = self.__getValue(self.fileStream[headInd])
613
+
614
+ return retDic
615
+
616
+ except mExc.MapleDataNotFoundException as dnfe:
617
+
618
+ raise mExc.MapleDataNotFoundException(self.fileName) from dnfe
619
+
620
+ except Exception as ex:
621
+
622
+ raise mExc.MapleException(ex) from ex
623
+ #
624
+ ############################
625
+ # Get tags list
626
+
627
+ def getTags(self, *headers: str) -> list[str]:
628
+
629
+ """
630
+ Get and return tags list from headers in Maple file(readFile)
631
+ """
632
+
633
+ retList = []
634
+
635
+ try:
636
+
637
+ # Find header
638
+
639
+ gotHeader, eInd, headInd = self._findHeader(headers)
640
+
641
+ if not gotHeader:
642
+
643
+ self.__headerNotFoundExceptionHandler(headInd, headers)
644
+
645
+ # Get tag list
646
+
647
+ while headInd < eInd - 1:
648
+
649
+ headInd += 1
650
+ lineTag = self.__getTag(self.fileStream[headInd])
651
+
652
+ if lineTag == "H":
653
+
654
+ headInd = self.__ToE(headInd)
655
+
656
+ else:
657
+
658
+ retList.append(lineTag)
659
+
660
+ return retList
661
+
662
+ except mExc.MapleDataNotFoundException as dnfe:
663
+
664
+ raise mExc.MapleDataNotFoundException(self.fileName) from dnfe
665
+
666
+ except Exception as ex:
667
+
668
+ raise mExc.MapleException(ex) from ex
669
+ #
670
+ #############################
671
+ # Delete header
672
+
673
+ def deleteHeader(self, delHead: str, willSave: bool = False, *Headers: str) -> bool:
674
+
675
+ try:
676
+
677
+ gotHeader, eInd, headInd = self._findHeader(Headers)
678
+
679
+ if not gotHeader:
680
+
681
+ self.__headerNotFoundExceptionHandler(headInd, Headers)
682
+
683
+ headInd = self.fileStream.index(f"{self.TAB_FORMAT * len(Headers)}H {delHead}\n", headInd, eInd)
684
+ eInd = self.__ToE(headInd)
685
+
686
+ self.fileStream = self.fileStream[:headInd] + self.fileStream[eInd + 1:]
687
+
688
+ # Save?
689
+
690
+ if willSave:
691
+
692
+ self._saveToFile()
693
+
694
+ # Refresh EOF index
695
+
696
+ self.eofIndex = self._findEof(headInd + 1)
697
+
698
+ except ValueError or mExc.MapleDataNotFoundException as ve:
699
+
700
+ raise mExc.MapleDataNotFoundException(self.fileName) from ve
701
+
702
+ except Exception as e:
703
+
704
+ raise mExc.MapleException(e) from e
705
+
706
+ return True
707
+
708
+ #
709
+ ############################
710
+ # Get headers list
711
+
712
+ def getHeaders(self, *headers: str) -> list:
713
+
714
+ """
715
+ Get and return headers list from headers in Maple file(readFile)
716
+ """
717
+
718
+ retList = []
719
+
720
+ try:
721
+
722
+ gotHeader, eInd, headInd = self._findHeader(headers)
723
+
724
+ if not gotHeader:
725
+
726
+ self.__headerNotFoundExceptionHandler(headInd, headers)
727
+
728
+ while headInd < eInd:
729
+
730
+ headInd += 1
731
+ fileLine = self.__removeWhiteSpace(self.fileStream[headInd])
732
+
733
+ if fileLine.startswith("H "):
734
+
735
+ retList.append(self.__getValue(fileLine))
736
+ headInd = self.__ToE(headInd)
737
+
738
+ except mExc.MapleDataNotFoundException as dnfe:
739
+
740
+ raise mExc.MapleDataNotFoundException(self.fileName) from dnfe
741
+
742
+ except Exception as ex:
743
+
744
+ raise mExc.MapleException(ex) from ex
745
+
746
+ return retList
747
+
748
+ """ * * * * * * * * * * * * * """
749
+ """
750
+ ToDo list:
751
+
752
+ * MapleTree *
753
+
754
+ - Ignore "CMT" tag as a comment line in MapleTree file.
755
+
756
+ """
757
+ """ * * * * * * * * * * * * * """