solentware-base 5.2__tar.gz → 5.2.2__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.
Files changed (79) hide show
  1. {solentware-base-5.2/solentware_base.egg-info → solentware_base-5.2.2}/PKG-INFO +2 -2
  2. {solentware-base-5.2 → solentware_base-5.2.2}/pyproject.toml +2 -2
  3. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_database.py +1 -1
  4. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_databasedu.py +3 -3
  5. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_db.py +14 -15
  6. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_db_tkinter.py +16 -15
  7. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dbdu.py +4 -4
  8. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dbdu_tkinter.py +4 -4
  9. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dpt.py +20 -12
  10. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_lmdb.py +10 -12
  11. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_lmdbdu.py +4 -4
  12. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_nosql.py +18 -30
  13. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_nosqldu.py +3 -3
  14. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_sqlite.py +37 -25
  15. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/find.py +4 -2
  16. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/record.py +5 -3
  17. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/where.py +97 -80
  18. {solentware-base-5.2 → solentware_base-5.2.2/solentware_base.egg-info}/PKG-INFO +2 -2
  19. {solentware-base-5.2 → solentware_base-5.2.2}/LICENCE +0 -0
  20. {solentware-base-5.2 → solentware_base-5.2.2}/MANIFEST.in +0 -0
  21. {solentware-base-5.2 → solentware_base-5.2.2}/README +0 -0
  22. {solentware-base-5.2 → solentware_base-5.2.2}/setup.cfg +0 -0
  23. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/__init__.py +0 -0
  24. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/apsw_database.py +0 -0
  25. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/apswdu_database.py +0 -0
  26. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/berkeleydb_database.py +0 -0
  27. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/berkeleydbdu_database.py +0 -0
  28. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/bsddb3_database.py +0 -0
  29. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/bsddb3du_database.py +0 -0
  30. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/__init__.py +0 -0
  31. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_bytebit.py +0 -0
  32. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_sqlitedu.py +0 -0
  33. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/bytebit.py +0 -0
  34. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/constants.py +0 -0
  35. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/cursor.py +0 -0
  36. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/filespec.py +0 -0
  37. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/findvalues.py +0 -0
  38. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/merge.py +0 -0
  39. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordset.py +0 -0
  40. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordsetbasecursor.py +0 -0
  41. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordsetcursor.py +0 -0
  42. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/segmentsize.py +0 -0
  43. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/tree.py +0 -0
  44. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/wherevalues.py +0 -0
  45. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tcl.py +0 -0
  46. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tkinter_database.py +0 -0
  47. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tkinterdu_database.py +0 -0
  48. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dpt_database.py +0 -0
  49. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dptdu_database.py +0 -0
  50. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dptfastload_database.py +0 -0
  51. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnu_database.py +0 -0
  52. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnu_module.py +0 -0
  53. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnudu_database.py +0 -0
  54. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/lmdb_database.py +0 -0
  55. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/lmdbdu_database.py +0 -0
  56. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/modulequery.py +0 -0
  57. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbm_database.py +0 -0
  58. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbm_module.py +0 -0
  59. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbmdu_database.py +0 -0
  60. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/sqlite3_database.py +0 -0
  61. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/sqlite3du_database.py +0 -0
  62. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/__init__.py +0 -0
  63. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4.py +0 -0
  64. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4_db.py +0 -0
  65. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4_sqlite.py +0 -0
  66. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/berkeleydb_du_splice_fix.py +0 -0
  67. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/compare_dpt_tape_files.py +0 -0
  68. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/create_database.py +0 -0
  69. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/sqlite_table_name_upgrade.py +0 -0
  70. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/traverse_dpt_tape_files.py +0 -0
  71. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/ui_base_3_to_4.py +0 -0
  72. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/unqlite_database.py +0 -0
  73. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/unqlitedu_database.py +0 -0
  74. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/vedis_database.py +0 -0
  75. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/vedisdu_database.py +0 -0
  76. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/SOURCES.txt +0 -0
  77. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/dependency_links.txt +0 -0
  78. {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/top_level.txt +0 -0
  79. {solentware-base-5.2 → solentware_base-5.2.2}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: solentware-base
3
- Version: 5.2
3
+ Version: 5.2.2
4
4
  Summary: Bitmapped record number databases.
5
5
  Author-email: Roger Marsh <roger.marsh@solentware.co.uk>
6
6
  License: Licence for solentware_base package
@@ -23,10 +23,10 @@ Project-URL: Homepage, http://www.solentware.co.uk
23
23
  Project-URL: Repository, https://github.com/RogerMarsh/solentware-base.git
24
24
  Project-URL: Bug Tracker, https://github.com/RogerMarsh/solentware-base/issues
25
25
  Classifier: License :: OSI Approved :: BSD License
26
- Classifier: Programming Language :: Python :: 3.8
27
26
  Classifier: Programming Language :: Python :: 3.9
28
27
  Classifier: Programming Language :: Python :: 3.10
29
28
  Classifier: Programming Language :: Python :: 3.11
29
+ Classifier: Programming Language :: Python :: 3.12
30
30
  Classifier: Operating System :: OS Independent
31
31
  Classifier: Topic :: Database
32
32
  Classifier: Intended Audience :: Developers
@@ -10,17 +10,17 @@ line-length = 79
10
10
 
11
11
  [project]
12
12
  name = "solentware-base"
13
- version = "5.2"
13
+ version = "5.2.2"
14
14
  authors = [
15
15
  { name="Roger Marsh", email="roger.marsh@solentware.co.uk" },
16
16
  ]
17
17
  description = "Bitmapped record number databases."
18
18
  classifiers = [
19
19
  "License :: OSI Approved :: BSD License",
20
- "Programming Language :: Python :: 3.8",
21
20
  "Programming Language :: Python :: 3.9",
22
21
  "Programming Language :: Python :: 3.10",
23
22
  "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
24
  "Operating System :: OS Independent",
25
25
  "Topic :: Database",
26
26
  "Intended Audience :: Developers",
@@ -81,7 +81,7 @@ class Database:
81
81
  """
82
82
  deletekey = instance.key.pack()
83
83
  instance.set_packed_value_and_indexes()
84
- high_record = self.get_high_record(dbset)
84
+ high_record = self.get_high_record_number(dbset)
85
85
  self.delete(dbset, deletekey, instance.srvalue)
86
86
  instance.srkey = self.encode_record_number(deletekey)
87
87
  srindex = instance.srindex
@@ -151,9 +151,9 @@ class Database(_database.Database):
151
151
  if values[-1] != record_number:
152
152
  values.append(record_number)
153
153
  if len(values) > SegmentSize.db_upper_conversion_limit:
154
- vsk = value_segments[
155
- key
156
- ] = SegmentSize.empty_bitarray.copy()
154
+ vsk = value_segments[key] = (
155
+ SegmentSize.empty_bitarray.copy()
156
+ )
157
157
  for j in values:
158
158
  vsk[j] = True
159
159
  vsk[record_number] = True
@@ -695,10 +695,8 @@ class Database(_database.Database):
695
695
  )
696
696
  return None
697
697
 
698
- # high_record will become high_record_number to fit changed
699
- # get_high_record.
700
698
  def note_freed_record_number_segment(
701
- self, dbset, segment, record_number_in_segment, high_record
699
+ self, dbset, segment, record_number_in_segment, high_record_number
702
700
  ):
703
701
  """Add existence bitmap segment to list with spare record numbers.
704
702
 
@@ -708,9 +706,9 @@ class Database(_database.Database):
708
706
  """
709
707
  del record_number_in_segment
710
708
  try:
711
- high_segment = divmod(high_record[0], SegmentSize.db_segment_size)[
712
- 0
713
- ]
709
+ high_segment = divmod(
710
+ high_record_number, SegmentSize.db_segment_size
711
+ )[0]
714
712
  except TypeError:
715
713
  # Implies attempt to delete record from empty database.
716
714
  # The delete method will have raised an exception if appropriate.
@@ -791,13 +789,14 @@ class Database(_database.Database):
791
789
  )
792
790
  return segment, record_number
793
791
 
794
- # Change to return just the record number, and the name to fit.
795
- # Only used in one place, and it is extra work to get the data in_nosql.
796
- def get_high_record(self, file):
792
+ def get_high_record_number(self, file):
797
793
  """Return the high existing record number in table for file."""
798
794
  cursor = self.table[file].cursor(txn=self.dbtxn)
799
795
  try:
800
- return cursor.last()
796
+ last = cursor.last()
797
+ if last is None:
798
+ return None
799
+ return last[0]
801
800
  finally:
802
801
  cursor.close()
803
802
 
@@ -1414,7 +1413,7 @@ class Database(_database.Database):
1414
1413
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1415
1414
  if keylike is None:
1416
1415
  return recordlist
1417
- pattern = b".*?" + keylike
1416
+ matcher = re.compile(keylike)
1418
1417
  cursor = self.table[SUBFILE_DELIMITER.join((file, field))].cursor(
1419
1418
  txn=self.dbtxn
1420
1419
  )
@@ -1422,7 +1421,7 @@ class Database(_database.Database):
1422
1421
  record = cursor.first()
1423
1422
  while record:
1424
1423
  key, value = record
1425
- if re.match(pattern, key, flags=re.IGNORECASE | re.DOTALL):
1424
+ if matcher.search(key):
1426
1425
  self.populate_recordset_segment(recordlist, value)
1427
1426
  record = cursor.next()
1428
1427
  finally:
@@ -1478,9 +1477,9 @@ class Database(_database.Database):
1478
1477
 
1479
1478
  Keys are in range set by combinations of ge, gt, le, and lt.
1480
1479
  """
1481
- if ge and gt:
1480
+ if isinstance(ge, bytes) and isinstance(gt, bytes):
1482
1481
  raise DatabaseError("Both 'ge' and 'gt' given in key range")
1483
- if le and lt:
1482
+ if isinstance(le, bytes) and isinstance(lt, bytes):
1484
1483
  raise DatabaseError("Both 'le' and 'lt' given in key range")
1485
1484
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1486
1485
  cursor = self.table[SUBFILE_DELIMITER.join((file, field))].cursor(
@@ -1490,7 +1489,7 @@ class Database(_database.Database):
1490
1489
  if ge is None and gt is None:
1491
1490
  record = cursor.first()
1492
1491
  else:
1493
- record = cursor.set_range(ge or gt)
1492
+ record = cursor.set_range(ge or gt or b"")
1494
1493
  if gt:
1495
1494
  while record:
1496
1495
  if record[0] > gt:
@@ -895,10 +895,8 @@ class Database(_database.Database):
895
895
  )
896
896
  return None
897
897
 
898
- # high_record will become high_record_number to fit changed
899
- # get_high_record.
900
898
  def note_freed_record_number_segment(
901
- self, dbset, segment, record_number_in_segment, high_record
899
+ self, dbset, segment, record_number_in_segment, high_record_number
902
900
  ):
903
901
  """Add existence bitmap segment to list with spare record numbers.
904
902
 
@@ -908,9 +906,9 @@ class Database(_database.Database):
908
906
  """
909
907
  del record_number_in_segment
910
908
  try:
911
- high_segment = divmod(high_record[0], SegmentSize.db_segment_size)[
912
- 0
913
- ]
909
+ high_segment = divmod(
910
+ high_record_number, SegmentSize.db_segment_size
911
+ )[0]
914
912
  except TypeError:
915
913
  # Implies attempt to delete record from empty database.
916
914
  # The delete method will have raised an exception if appropriate.
@@ -1012,16 +1010,17 @@ class Database(_database.Database):
1012
1010
  tcl_tk_call(tuple(command))
1013
1011
  return segment, record_number
1014
1012
 
1015
- # Change to return just the record number, and the name to fit.
1016
- # Only used in one place, and it is extra work to get the data in_nosql.
1017
- def get_high_record(self, file):
1013
+ def get_high_record_number(self, file):
1018
1014
  """Return the high existing record number in table for file."""
1019
1015
  command = [self.table[file], "cursor"]
1020
1016
  if self.dbtxn:
1021
1017
  command.extend(["-txn", self.dbtxn])
1022
1018
  cursor = tcl_tk_call(tuple(command))
1023
1019
  try:
1024
- return tcl_tk_call((cursor, "get", "-last")) or None
1020
+ last = tcl_tk_call((cursor, "get", "-last")) or None
1021
+ if last is None:
1022
+ return None
1023
+ return last[0]
1025
1024
  finally:
1026
1025
  tcl_tk_call((cursor, "close"))
1027
1026
 
@@ -1793,7 +1792,7 @@ class Database(_database.Database):
1793
1792
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1794
1793
  if keylike is None:
1795
1794
  return recordlist
1796
- pattern = b".*?" + keylike
1795
+ matcher = re.compile(keylike)
1797
1796
  command = [
1798
1797
  self.table[SUBFILE_DELIMITER.join((file, field))],
1799
1798
  "cursor",
@@ -1805,7 +1804,7 @@ class Database(_database.Database):
1805
1804
  record = tcl_tk_call((cursor, "get", "-first"))
1806
1805
  while record:
1807
1806
  key, value = record[0]
1808
- if re.match(pattern, key, flags=re.IGNORECASE | re.DOTALL):
1807
+ if matcher.search(key):
1809
1808
  self.populate_recordset_segment(recordlist, value)
1810
1809
  record = tcl_tk_call((cursor, "get", "-next"))
1811
1810
  finally:
@@ -1872,9 +1871,9 @@ class Database(_database.Database):
1872
1871
 
1873
1872
  Keys are in range set by combinations of ge, gt, le, and lt.
1874
1873
  """
1875
- if ge and gt:
1874
+ if isinstance(ge, str) and isinstance(gt, str):
1876
1875
  raise DatabaseError("Both 'ge' and 'gt' given in key range")
1877
- if le and lt:
1876
+ if isinstance(le, str) and isinstance(lt, str):
1878
1877
  raise DatabaseError("Both 'le' and 'lt' given in key range")
1879
1878
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1880
1879
  command = [
@@ -1888,7 +1887,9 @@ class Database(_database.Database):
1888
1887
  if ge is None and gt is None:
1889
1888
  record = tcl_tk_call((cursor, "get", "-first"))
1890
1889
  else:
1891
- record = tcl_tk_call((cursor, "get", "-set_range", ge or gt))
1890
+ record = tcl_tk_call(
1891
+ (cursor, "get", "-set_range", ge or gt or "")
1892
+ )
1892
1893
  if gt:
1893
1894
  while record:
1894
1895
  record0 = record[0]
@@ -553,10 +553,10 @@ class Database(_databasedu.Database):
553
553
  new_segment = make_segment_from_item(item)
554
554
  new_segment |= existing_segment
555
555
  new_segment.normalize()
556
- item[
557
- -2
558
- ] = self.database.encode_number_for_sequential_file_dump(
559
- new_segment.count_records(), 2
556
+ item[-2] = (
557
+ self.database.encode_number_for_sequential_file_dump(
558
+ new_segment.count_records(), 2
559
+ )
560
560
  )
561
561
  if int.from_bytes(high[-2], byteorder="big") == 1:
562
562
  item[-1] = segment_table.append(
@@ -700,10 +700,10 @@ class Database(_databasedu.Database):
700
700
  new_segment = make_segment_from_item(item)
701
701
  new_segment |= existing_segment
702
702
  new_segment.normalize()
703
- item[
704
- -2
705
- ] = self.database.encode_number_for_sequential_file_dump(
706
- new_segment.count_records(), 2
703
+ item[-2] = (
704
+ self.database.encode_number_for_sequential_file_dump(
705
+ new_segment.count_records(), 2
706
+ )
707
707
  )
708
708
  if int.from_bytes(high[-2], byteorder="big") == 1:
709
709
  item[-1] = tcl_tk_call(
@@ -849,14 +849,14 @@ class Database(_database.Database):
849
849
  dptapi.APIFieldValue(""),
850
850
  )
851
851
  )
852
- matcher = re.compile(".*?" + keylike, flags=re.IGNORECASE | re.DOTALL)
852
+ matcher = re.compile(keylike)
853
853
  dvcursor = dptfile.table_connection.OpenDirectValueCursor(
854
854
  dptapi.APIFindValuesSpecification(dptfile.secondary[field])
855
855
  )
856
856
  dvcursor.GotoFirst()
857
857
  while dvcursor.Accessible():
858
858
  value = dvcursor.GetCurrentValue()
859
- if matcher.match(value.ExtractString()):
859
+ if matcher.search(value.ExtractString()):
860
860
  vfs = _DPTFoundSet(
861
861
  dptfile,
862
862
  dptfile.table_connection.FindRecords(
@@ -961,9 +961,9 @@ class Database(_database.Database):
961
961
 
962
962
  cache_size is not relevant to DPT.
963
963
  """
964
- if ge and gt:
964
+ if isinstance(ge, str) and isinstance(gt, str):
965
965
  raise DatabaseError("Both 'ge' and 'gt' given in key range")
966
- if le and lt:
966
+ if isinstance(le, str) and isinstance(lt, str):
967
967
  raise DatabaseError("Both 'le' and 'lt' given in key range")
968
968
  if ge is None and gt is None and le is None and lt is None:
969
969
  return self.recordlist_all(file, field, cache_size=cache_size)
@@ -975,8 +975,8 @@ class Database(_database.Database):
975
975
  dptfile.table_connection.FindRecords(
976
976
  dptapi.APIFindSpecification(
977
977
  dptfile.secondary[field],
978
- dptapi.FD_GE if ge else dptapi.FD_GT,
979
- dptapi.APIFieldValue(ge or gt),
978
+ dptapi.FD_GE if ge is not None else dptapi.FD_GT,
979
+ dptapi.APIFieldValue(ge or gt or ""),
980
980
  )
981
981
  ),
982
982
  )
@@ -986,24 +986,32 @@ class Database(_database.Database):
986
986
  dptfile.table_connection.FindRecords(
987
987
  dptapi.APIFindSpecification(
988
988
  dptfile.secondary[field],
989
- dptapi.FD_LE if le else dptapi.FD_LT,
990
- dptapi.APIFieldValue(le or lt),
989
+ dptapi.FD_LE if le is not None else dptapi.FD_LT,
990
+ dptapi.APIFieldValue(le or lt or ""),
991
991
  )
992
992
  ),
993
993
  )
994
994
  else:
995
995
  if ge:
996
- range_ = dptapi.FD_RANGE_GE_LE if le else dptapi.FD_RANGE_GE_LT
996
+ range_ = (
997
+ dptapi.FD_RANGE_GE_LE
998
+ if le is not None
999
+ else dptapi.FD_RANGE_GE_LT
1000
+ )
997
1001
  else:
998
- range_ = dptapi.FD_RANGE_GT_LE if le else dptapi.FD_RANGE_GT_LT
1002
+ range_ = (
1003
+ dptapi.FD_RANGE_GT_LE
1004
+ if le is not None
1005
+ else dptapi.FD_RANGE_GT_LT
1006
+ )
999
1007
  foundset = _DPTFoundSet(
1000
1008
  dptfile,
1001
1009
  dptfile.table_connection.FindRecords(
1002
1010
  dptapi.APIFindSpecification(
1003
1011
  dptfile.secondary[field],
1004
1012
  range_,
1005
- dptapi.APIFieldValue(ge or gt),
1006
- dptapi.APIFieldValue(le or lt),
1013
+ dptapi.APIFieldValue(ge or gt or ""),
1014
+ dptapi.APIFieldValue(le or lt or ""),
1007
1015
  )
1008
1016
  ),
1009
1017
  )
@@ -743,10 +743,8 @@ class Database(_database.Database):
743
743
  )
744
744
  return None
745
745
 
746
- # high_record will become high_record_number to fit changed
747
- # get_high_record.
748
746
  def note_freed_record_number_segment(
749
- self, dbset, segment, record_number_in_segment, high_record
747
+ self, dbset, segment, record_number_in_segment, high_record_number
750
748
  ):
751
749
  """Add existence bitmap segment to list with spare record numbers.
752
750
 
@@ -756,7 +754,9 @@ class Database(_database.Database):
756
754
  """
757
755
  del record_number_in_segment
758
756
  try:
759
- high_segment = divmod(high_record, SegmentSize.db_segment_size)[0]
757
+ high_segment = divmod(
758
+ high_record_number, SegmentSize.db_segment_size
759
+ )[0]
760
760
  except TypeError:
761
761
  # Implies attempt to delete record from empty database.
762
762
  # The delete method will have raised an exception if appropriate.
@@ -844,9 +844,7 @@ class Database(_database.Database):
844
844
  )
845
845
  return segment, record_number
846
846
 
847
- # Change to return just the record number, and the name to fit.
848
- # Only used in one place, and it is extra work to get the data in_nosql.
849
- def get_high_record(self, file):
847
+ def get_high_record_number(self, file):
850
848
  """Return the high existing record number in table for file."""
851
849
  with self.dbtxn.transaction.cursor(
852
850
  self.table[file].datastore
@@ -1482,14 +1480,14 @@ class Database(_database.Database):
1482
1480
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1483
1481
  if keylike is None:
1484
1482
  return recordlist
1485
- pattern = b".*?" + keylike
1483
+ matcher = re.compile(keylike)
1486
1484
  with self.dbtxn.transaction.cursor(
1487
1485
  self.table[SUBFILE_DELIMITER.join((file, field))].datastore
1488
1486
  ) as cursor:
1489
1487
  record = cursor.first()
1490
1488
  while record:
1491
1489
  key, value = cursor.item()
1492
- if re.match(pattern, key, flags=re.IGNORECASE | re.DOTALL):
1490
+ if matcher.search(key):
1493
1491
  self.populate_recordset_segment(recordlist, value)
1494
1492
  record = cursor.next()
1495
1493
  return recordlist
@@ -1540,9 +1538,9 @@ class Database(_database.Database):
1540
1538
 
1541
1539
  Keys are in range set by combinations of ge, gt, le, and lt.
1542
1540
  """
1543
- if ge and gt:
1541
+ if isinstance(ge, bytes) and isinstance(gt, bytes):
1544
1542
  raise DatabaseError("Both 'ge' and 'gt' given in key range")
1545
- if le and lt:
1543
+ if isinstance(le, bytes) and isinstance(lt, bytes):
1546
1544
  raise DatabaseError("Both 'le' and 'lt' given in key range")
1547
1545
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1548
1546
  with self.dbtxn.transaction.cursor(
@@ -1551,7 +1549,7 @@ class Database(_database.Database):
1551
1549
  if ge is None and gt is None:
1552
1550
  record = cursor.first()
1553
1551
  else:
1554
- record = cursor.set_range(ge or gt)
1552
+ record = cursor.set_range(ge or gt or b"")
1555
1553
  if gt:
1556
1554
  while record:
1557
1555
  record = cursor.item()
@@ -611,10 +611,10 @@ class Database(_databasedu.Database):
611
611
  new_segment = make_segment_from_item(item)
612
612
  new_segment |= existing_segment
613
613
  new_segment.normalize()
614
- item[
615
- -2
616
- ] = self.database.encode_number_for_sequential_file_dump(
617
- new_segment.count_records(), 2
614
+ item[-2] = (
615
+ self.database.encode_number_for_sequential_file_dump(
616
+ new_segment.count_records(), 2
617
+ )
618
618
  )
619
619
  if int.from_bytes(item[-2], byteorder="big") == 1:
620
620
  item[-1] = write_segment_value(
@@ -108,9 +108,9 @@ class Database(_database.Database):
108
108
  continue
109
109
  for fieldattr in NOSQL_FIELDATTS:
110
110
  if fieldattr not in filedesc[FIELDS][fieldname]:
111
- filedesc[FIELDS][fieldname][
112
- fieldattr
113
- ] = SECONDARY_FIELDATTS[fieldattr]
111
+ filedesc[FIELDS][fieldname][fieldattr] = (
112
+ SECONDARY_FIELDATTS[fieldattr]
113
+ )
114
114
  self.specification = specification
115
115
  self.segment_size_bytes = segment_size_bytes
116
116
  self.dbenv = None
@@ -648,15 +648,15 @@ class Database(_database.Database):
648
648
 
649
649
  def next_record_number(self, dbset):
650
650
  """Return high record number plus 1."""
651
- high_record = self.get_high_record(dbset)
652
- if high_record is None:
651
+ high_record_number = self.get_high_record_number(dbset)
652
+ if high_record_number is None:
653
653
  return 0
654
- return high_record[0] + 1
654
+ return high_record_number + 1
655
655
 
656
656
  # high_record will become high_record_number to fit changed
657
- # get_high_record method.
657
+ # get_high_record_number method.
658
658
  def note_freed_record_number_segment(
659
- self, dbset, segment, record_number_in_segment, high_record
659
+ self, dbset, segment, record_number_in_segment, high_record_number
660
660
  ):
661
661
  """Add existence bitmap segment to list with spare record numbers.
662
662
 
@@ -666,9 +666,9 @@ class Database(_database.Database):
666
666
  """
667
667
  del record_number_in_segment
668
668
  try:
669
- high_segment = divmod(high_record[0], SegmentSize.db_segment_size)[
670
- 0
671
- ]
669
+ high_segment = divmod(
670
+ high_record_number, SegmentSize.db_segment_size
671
+ )[0]
672
672
  except TypeError:
673
673
  # Implies attempt to delete record from empty database.
674
674
  # The delete method will have raised an exception if appropriate.
@@ -738,24 +738,12 @@ class Database(_database.Database):
738
738
  ebmcf.high_record_number = max(ebmcf.high_record_number, putkey)
739
739
  return segment, record_number
740
740
 
741
- # Change to return just the record number, and the name to fit.
742
- # Only used in one place, and it is extra work to get the data in_nosql.
743
- # Also actually getting the record does not prove it is the high record; in
744
- # _sqlite and _db asking for high record returns (key, data) where key will
745
- # be the high record number.
746
- def get_high_record(self, file):
741
+ def get_high_record_number(self, file):
747
742
  """Return the high existing record number in table for file."""
748
743
  high_record_number = self.ebm_control[file].high_record_number
749
744
  if high_record_number == -1:
750
745
  return None
751
- return (
752
- high_record_number,
753
- self.dbenv[
754
- SUBFILE_DELIMITER.join(
755
- (self.table_data[file], str(high_record_number))
756
- )
757
- ],
758
- )
746
+ return high_record_number
759
747
 
760
748
  def add_record_to_field_value(
761
749
  self, file, field, key, segment, record_number
@@ -1229,7 +1217,7 @@ class Database(_database.Database):
1229
1217
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1230
1218
  if keylike is None:
1231
1219
  return recordlist
1232
- matcher = re.compile(".*?" + keylike, flags=re.IGNORECASE | re.DOTALL)
1220
+ matcher = re.compile(keylike)
1233
1221
  db = self.dbenv
1234
1222
  fieldtree = self.trees[SUBFILE_DELIMITER.join((file, field))]
1235
1223
  cursor = tree.Cursor(fieldtree)
@@ -1238,7 +1226,7 @@ class Database(_database.Database):
1238
1226
  k = cursor.next()
1239
1227
  if k is None:
1240
1228
  break
1241
- if not matcher.match(k):
1229
+ if not matcher.search(k):
1242
1230
  continue
1243
1231
  self.populate_recordset(
1244
1232
  recordlist,
@@ -1322,9 +1310,9 @@ class Database(_database.Database):
1322
1310
  ("'", field, "' field in '", file, "' file is not ordered")
1323
1311
  )
1324
1312
  )
1325
- if ge and gt:
1313
+ if isinstance(ge, str) and isinstance(gt, str):
1326
1314
  raise DatabaseError("Both 'ge' and 'gt' given in key range")
1327
- if le and lt:
1315
+ if isinstance(le, str) and isinstance(lt, str):
1328
1316
  raise DatabaseError("Both 'le' and 'lt' given in key range")
1329
1317
  recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
1330
1318
  db = self.dbenv
@@ -1334,7 +1322,7 @@ class Database(_database.Database):
1334
1322
  if ge is None and gt is None:
1335
1323
  k = cursor.first()
1336
1324
  else:
1337
- k = cursor.nearest(ge or gt)
1325
+ k = cursor.nearest(ge or gt or "")
1338
1326
  if gt:
1339
1327
  while k is not None:
1340
1328
  if k > gt:
@@ -121,9 +121,9 @@ class Database(_databasedu.Database):
121
121
  ebmc = self.ebm_control[file]
122
122
  tes = ebmc.table_ebm_segments
123
123
  insertion_point = bisect_right(tes, segment)
124
- self.dbenv[
125
- SUBFILE_DELIMITER.join((ebmc.ebm_table, str(segment)))
126
- ] = repr(self.existence_bit_maps[file][segment].tobytes())
124
+ self.dbenv[SUBFILE_DELIMITER.join((ebmc.ebm_table, str(segment)))] = (
125
+ repr(self.existence_bit_maps[file][segment].tobytes())
126
+ )
127
127
  if not (tes and tes[insertion_point - 1] == segment):
128
128
  tes.insert(insertion_point, segment)
129
129
  self.dbenv[ebmc.ebm_table] = repr(tes)