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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: TSVZ
3
- Version: 2.66
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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.66'
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
- col_items = [str(row[c]) for row in data]
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
- outTable.append(row_format.format(*row))
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: {header.strip()}",teeLogger=teeLogger)
230
- __teePrintOrNot(f"First line: {line}",teeLogger=teeLogger)
231
- if not line.lower().replace(' ','').startswith(header.strip().lower().replace(' ','')):
232
- __teePrintOrNot(f"Header mismatch: \n{line} \n!= \n{header.strip()}",teeLogger=teeLogger)
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 time.time_ns()
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 = time.time_ns()
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 = time.time_ns()
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 = time.time_ns()
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 = time.time_ns()
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 = time.time_ns()
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
@@ -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