TSVZ 2.66__py3-none-any.whl → 2.70__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.
- {TSVZ-2.66.dist-info → TSVZ-2.70.dist-info}/METADATA +10 -2
- TSVZ-2.70.dist-info/RECORD +7 -0
- {TSVZ-2.66.dist-info → TSVZ-2.70.dist-info}/WHEEL +1 -1
- TSVZ.py +58 -15
- TSVZ-2.66.dist-info/RECORD +0 -7
- {TSVZ-2.66.dist-info → TSVZ-2.70.dist-info}/LICENSE +0 -0
- {TSVZ-2.66.dist-info → TSVZ-2.70.dist-info}/entry_points.txt +0 -0
- {TSVZ-2.66.dist-info → TSVZ-2.70.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: TSVZ
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.70
|
|
4
4
|
Summary: An simple in memory wrapper around a TSV file to function as a database
|
|
5
5
|
Home-page: https://github.com/yufei-pan/TSVZ
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -11,6 +11,14 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.6
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
14
22
|
|
|
15
23
|
This lib provides some helper funtions to interact with tsv ( tab seperated values ) files.
|
|
16
24
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
TSVZ.py,sha256=mmSFgfDv6IFQGoU_ggsHM0qJGX0jDAvfi4o-xH8k8-k,44205
|
|
2
|
+
TSVZ-2.70.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
TSVZ-2.70.dist-info/METADATA,sha256=4uvp786csTypMiA_ozs2ySTjFHn_bJ_t-61aJi6GwPY,1871
|
|
4
|
+
TSVZ-2.70.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
5
|
+
TSVZ-2.70.dist-info/entry_points.txt,sha256=WeXidyV5yKCRLaVsnAY35xGa08QgytOfvr1CK9aescI,60
|
|
6
|
+
TSVZ-2.70.dist-info/top_level.txt,sha256=OPx4LvOpaYykaos7oL_jGaObSWXxLzhHiWLuz-K147g,5
|
|
7
|
+
TSVZ-2.70.dist-info/RECORD,,
|
TSVZ.py
CHANGED
|
@@ -10,23 +10,39 @@ if os.name == 'nt':
|
|
|
10
10
|
elif os.name == 'posix':
|
|
11
11
|
import fcntl
|
|
12
12
|
|
|
13
|
-
version = '2.
|
|
13
|
+
version = '2.70'
|
|
14
14
|
author = 'pan@zopyr.us'
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def pretty_format_table(data):
|
|
18
|
+
version = 1.0
|
|
18
19
|
if not data:
|
|
19
|
-
return
|
|
20
|
+
return ''
|
|
20
21
|
if type(data) == str:
|
|
21
22
|
data = data.strip('\n').split('\n')
|
|
23
|
+
data = [line.split('\t') for line in data]
|
|
24
|
+
elif isinstance(data, dict):
|
|
25
|
+
# flatten the 2D dict to a list of lists
|
|
26
|
+
if isinstance(next(iter(data.values())), dict):
|
|
27
|
+
tempData = [['key'] + list(next(iter(data.values())).keys())]
|
|
28
|
+
tempData.extend( [[key] + list(value.values()) for key, value in data.items()])
|
|
29
|
+
data = tempData
|
|
30
|
+
else:
|
|
31
|
+
# it is a dict of lists
|
|
32
|
+
data = [[key] + list(value) for key, value in data.items()]
|
|
22
33
|
elif type(data) != list:
|
|
23
34
|
data = list(data)
|
|
35
|
+
# format the list into 2d list of list of strings
|
|
36
|
+
if isinstance(data[0], dict):
|
|
37
|
+
tempData = [data[0].keys()]
|
|
38
|
+
tempData.extend([list(item.values()) for item in data])
|
|
39
|
+
data = tempData
|
|
40
|
+
data = [[str(item) for item in row] for row in data]
|
|
24
41
|
num_cols = len(data[0])
|
|
25
42
|
col_widths = [0] * num_cols
|
|
26
43
|
# Calculate the maximum width of each column
|
|
27
44
|
for c in range(num_cols):
|
|
28
|
-
|
|
29
|
-
col_widths[c] = max(len(item) for item in col_items)
|
|
45
|
+
col_widths[c] = max(len(row[c]) for row in data)
|
|
30
46
|
# Build the row format string
|
|
31
47
|
row_format = ' | '.join('{{:<{}}}'.format(width) for width in col_widths)
|
|
32
48
|
# Print the header
|
|
@@ -35,7 +51,11 @@ def pretty_format_table(data):
|
|
|
35
51
|
outTable.append(row_format.format(*header))
|
|
36
52
|
outTable.append('-+-'.join('-' * width for width in col_widths))
|
|
37
53
|
for row in data[1:]:
|
|
38
|
-
|
|
54
|
+
# if the row is empty, print an divider
|
|
55
|
+
if not any(row):
|
|
56
|
+
outTable.append('-+-'.join('-' * width for width in col_widths))
|
|
57
|
+
else:
|
|
58
|
+
outTable.append(row_format.format(*row))
|
|
39
59
|
return '\n'.join(outTable) + '\n'
|
|
40
60
|
|
|
41
61
|
def __teePrintOrNot(message,level = 'info',teeLogger = None):
|
|
@@ -225,11 +245,15 @@ def lineContainHeader(header,line,verbose = False,teeLogger = None,strict = Fals
|
|
|
225
245
|
Returns:
|
|
226
246
|
bool: True if the header matches the line, False otherwise.
|
|
227
247
|
"""
|
|
248
|
+
escapedHeader = repr(header.strip())
|
|
249
|
+
escapedLine = repr(line.strip())
|
|
228
250
|
if verbose:
|
|
229
|
-
__teePrintOrNot(f"Header: {
|
|
230
|
-
__teePrintOrNot(f"First line: {
|
|
231
|
-
|
|
232
|
-
|
|
251
|
+
__teePrintOrNot(f"Header: \n{escapedHeader}",teeLogger=teeLogger)
|
|
252
|
+
__teePrintOrNot(f"First line: \n{escapedLine}",teeLogger=teeLogger)
|
|
253
|
+
headerList = header.strip().lower().split('\t')
|
|
254
|
+
lineList = line.strip().lower().split('\t')
|
|
255
|
+
if len(headerList) != len(lineList) or any([headerList[i] not in lineList[i] for i in range(len(headerList))]):
|
|
256
|
+
__teePrintOrNot(f"Header mismatch: \n{escapedLine} \n!= \n{escapedHeader}",teeLogger=teeLogger)
|
|
233
257
|
if strict:
|
|
234
258
|
raise Exception("Data format error! Header mismatch")
|
|
235
259
|
return False
|
|
@@ -333,6 +357,13 @@ def appendTSV(fileName,lineToAppend,teeLogger = None,header = '',createIfNotExis
|
|
|
333
357
|
return
|
|
334
358
|
if type(lineToAppend) == str:
|
|
335
359
|
lineToAppend = lineToAppend.strip().split('\t')
|
|
360
|
+
else:
|
|
361
|
+
for i in range(len(lineToAppend)):
|
|
362
|
+
if type(lineToAppend[i]) != str:
|
|
363
|
+
try:
|
|
364
|
+
lineToAppend[i] = str(lineToAppend[i])
|
|
365
|
+
except Exception as e:
|
|
366
|
+
lineToAppend[i] = str(e)
|
|
336
367
|
|
|
337
368
|
with open(fileName, mode ='r+b')as file:
|
|
338
369
|
correctColumnNum = len(lineToAppend)
|
|
@@ -384,12 +415,22 @@ def clearTSV(fileName,teeLogger = None,header = '',verifyHeader = False,verbose
|
|
|
384
415
|
__teePrintOrNot(f"Cleared {fileName}",teeLogger=teeLogger)
|
|
385
416
|
|
|
386
417
|
def getFileUpdateTimeNs(fileName):
|
|
418
|
+
# return 0 if the file does not exist
|
|
419
|
+
if not os.path.isfile(fileName):
|
|
420
|
+
return 0
|
|
387
421
|
try:
|
|
388
422
|
return os.stat(fileName).st_mtime_ns
|
|
389
423
|
except:
|
|
390
424
|
__teePrintOrNot(f"Failed to get file update time for {fileName}",'error')
|
|
391
|
-
return
|
|
425
|
+
return get_time_ns()
|
|
392
426
|
|
|
427
|
+
def get_time_ns():
|
|
428
|
+
try:
|
|
429
|
+
return time.time_ns()
|
|
430
|
+
except:
|
|
431
|
+
# try to get the time in nanoseconds
|
|
432
|
+
return int(time.time()*1e9)
|
|
433
|
+
|
|
393
434
|
# create a tsv class that functions like a ordered dictionary but will update the file when modified
|
|
394
435
|
class TSVZed(OrderedDict):
|
|
395
436
|
def __teePrintOrNot(self,message,level = 'info'):
|
|
@@ -503,7 +544,7 @@ class TSVZed(OrderedDict):
|
|
|
503
544
|
if self.verbose:
|
|
504
545
|
self.__teePrintOrNot(f"Appending {key} to the appendQueue")
|
|
505
546
|
self.appendQueue.append('\t'.join(value))
|
|
506
|
-
self.lastUpdateTime =
|
|
547
|
+
self.lastUpdateTime = get_time_ns()
|
|
507
548
|
# if not self.appendThread.is_alive():
|
|
508
549
|
# self.commitAppendToFile()
|
|
509
550
|
# else:
|
|
@@ -521,7 +562,7 @@ class TSVZed(OrderedDict):
|
|
|
521
562
|
if self.memoryOnly:
|
|
522
563
|
return
|
|
523
564
|
self.__appendEmptyLine(key)
|
|
524
|
-
self.lastUpdateTime =
|
|
565
|
+
self.lastUpdateTime = get_time_ns()
|
|
525
566
|
|
|
526
567
|
def __appendEmptyLine(self,key):
|
|
527
568
|
self.dirty = True
|
|
@@ -614,7 +655,7 @@ memoryOnly:{self.memoryOnly}
|
|
|
614
655
|
key, value = super().popitem(last)
|
|
615
656
|
if not self.memoryOnly:
|
|
616
657
|
self.__appendEmptyLine(key)
|
|
617
|
-
self.lastUpdateTime =
|
|
658
|
+
self.lastUpdateTime = get_time_ns()
|
|
618
659
|
return key, value
|
|
619
660
|
|
|
620
661
|
__marker = object()
|
|
@@ -632,7 +673,7 @@ memoryOnly:{self.memoryOnly}
|
|
|
632
673
|
value = super().pop(key)
|
|
633
674
|
if not self.memoryOnly:
|
|
634
675
|
self.__appendEmptyLine(key)
|
|
635
|
-
self.lastUpdateTime =
|
|
676
|
+
self.lastUpdateTime = get_time_ns()
|
|
636
677
|
return value
|
|
637
678
|
|
|
638
679
|
def move_to_end(self, key, last=True):
|
|
@@ -647,7 +688,7 @@ memoryOnly:{self.memoryOnly}
|
|
|
647
688
|
self.__teePrintOrNot(f"rewrite_on_exit set to True")
|
|
648
689
|
if self.verbose:
|
|
649
690
|
self.__teePrintOrNot(f"Warning: Trying to move Key {key} moved to {'end' if last else 'beginning'} Need to resync for changes to apply to disk")
|
|
650
|
-
self.lastUpdateTime =
|
|
691
|
+
self.lastUpdateTime = get_time_ns()
|
|
651
692
|
return self
|
|
652
693
|
|
|
653
694
|
@classmethod
|
|
@@ -777,6 +818,8 @@ memoryOnly:{self.memoryOnly}
|
|
|
777
818
|
def checkExternalChanges(self):
|
|
778
819
|
if self.deSynced:
|
|
779
820
|
return self
|
|
821
|
+
if not self.monitor_external_changes:
|
|
822
|
+
return self
|
|
780
823
|
realExternalFileUpdateTime = getFileUpdateTimeNs(self._fileName)
|
|
781
824
|
if self.externalFileUpdateTime < realExternalFileUpdateTime:
|
|
782
825
|
self.deSynced = True
|
TSVZ-2.66.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
TSVZ.py,sha256=ttjNgB9aKnwmA4Zvp0xhhVKn2GUbgqSye1TwEppWXDg,42626
|
|
2
|
-
TSVZ-2.66.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
-
TSVZ-2.66.dist-info/METADATA,sha256=b02u5PsHzIfP1jy9GXFlZ-arcGQSi88siqVnrXkJmsY,1689
|
|
4
|
-
TSVZ-2.66.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
5
|
-
TSVZ-2.66.dist-info/entry_points.txt,sha256=WeXidyV5yKCRLaVsnAY35xGa08QgytOfvr1CK9aescI,60
|
|
6
|
-
TSVZ-2.66.dist-info/top_level.txt,sha256=OPx4LvOpaYykaos7oL_jGaObSWXxLzhHiWLuz-K147g,5
|
|
7
|
-
TSVZ-2.66.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|