solentware-base 5.2.3__tar.gz → 5.4__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 (80) hide show
  1. {solentware_base-5.2.3/solentware_base.egg-info → solentware_base-5.4}/PKG-INFO +1 -1
  2. {solentware_base-5.2.3 → solentware_base-5.4}/pyproject.toml +1 -1
  3. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_database.py +4 -4
  4. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_databasedu.py +11 -5
  5. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_db.py +130 -2
  6. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_db_tkinter.py +187 -2
  7. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_dbdu.py +2 -3
  8. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_dbdu_tkinter.py +2 -3
  9. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_dpt.py +523 -318
  10. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_lmdb.py +126 -0
  11. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_lmdbdu.py +2 -3
  12. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_nosql.py +102 -3
  13. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_sqlite.py +358 -2
  14. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_sqlitedu.py +2 -3
  15. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/constants.py +1 -0
  16. solentware_base-5.4/solentware_base/core/merge.py +83 -0
  17. solentware_base-5.2.3/solentware_base/core/merge.py → solentware_base-5.4/solentware_base/core/sortsequential.py +69 -87
  18. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/dptdu_database.py +180 -5
  19. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/ndbm_database.py +1 -1
  20. {solentware_base-5.2.3 → solentware_base-5.4/solentware_base.egg-info}/PKG-INFO +1 -1
  21. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base.egg-info/SOURCES.txt +1 -0
  22. {solentware_base-5.2.3 → solentware_base-5.4}/LICENCE +0 -0
  23. {solentware_base-5.2.3 → solentware_base-5.4}/MANIFEST.in +0 -0
  24. {solentware_base-5.2.3 → solentware_base-5.4}/README +0 -0
  25. {solentware_base-5.2.3 → solentware_base-5.4}/setup.cfg +0 -0
  26. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/__init__.py +0 -0
  27. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/apsw_database.py +0 -0
  28. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/apswdu_database.py +0 -0
  29. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/berkeleydb_database.py +0 -0
  30. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/berkeleydbdu_database.py +0 -0
  31. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/bsddb3_database.py +0 -0
  32. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/bsddb3du_database.py +0 -0
  33. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/__init__.py +0 -0
  34. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_bytebit.py +0 -0
  35. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/_nosqldu.py +0 -0
  36. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/bytebit.py +0 -0
  37. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/cursor.py +0 -0
  38. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/filespec.py +0 -0
  39. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/find.py +0 -0
  40. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/findvalues.py +0 -0
  41. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/record.py +0 -0
  42. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/recordset.py +0 -0
  43. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/recordsetbasecursor.py +0 -0
  44. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/recordsetcursor.py +0 -0
  45. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/segmentsize.py +0 -0
  46. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/tree.py +0 -0
  47. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/where.py +0 -0
  48. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/core/wherevalues.py +0 -0
  49. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/db_tcl.py +0 -0
  50. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/db_tkinter_database.py +0 -0
  51. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/db_tkinterdu_database.py +0 -0
  52. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/dpt_database.py +0 -0
  53. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/dptfastload_database.py +0 -0
  54. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/gnu_database.py +0 -0
  55. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/gnu_module.py +0 -0
  56. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/gnudu_database.py +0 -0
  57. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/lmdb_database.py +0 -0
  58. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/lmdbdu_database.py +0 -0
  59. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/modulequery.py +0 -0
  60. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/ndbm_module.py +0 -0
  61. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/ndbmdu_database.py +0 -0
  62. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/sqlite3_database.py +0 -0
  63. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/sqlite3du_database.py +0 -0
  64. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/__init__.py +0 -0
  65. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/base_3_to_4.py +0 -0
  66. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/base_3_to_4_db.py +0 -0
  67. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/base_3_to_4_sqlite.py +0 -0
  68. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/berkeleydb_du_splice_fix.py +0 -0
  69. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/compare_dpt_tape_files.py +0 -0
  70. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/create_database.py +0 -0
  71. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/sqlite_table_name_upgrade.py +0 -0
  72. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/traverse_dpt_tape_files.py +0 -0
  73. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/tools/ui_base_3_to_4.py +0 -0
  74. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/unqlite_database.py +0 -0
  75. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/unqlitedu_database.py +0 -0
  76. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/vedis_database.py +0 -0
  77. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base/vedisdu_database.py +0 -0
  78. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base.egg-info/dependency_links.txt +0 -0
  79. {solentware_base-5.2.3 → solentware_base-5.4}/solentware_base.egg-info/top_level.txt +0 -0
  80. {solentware_base-5.2.3 → solentware_base-5.4}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solentware-base
3
- Version: 5.2.3
3
+ Version: 5.4
4
4
  Summary: Bitmapped record number databases.
5
5
  Author-email: Roger Marsh <roger.marsh@solentware.co.uk>
6
6
  License-Expression: BSD-3-Clause
@@ -10,7 +10,7 @@ line-length = 79
10
10
 
11
11
  [project]
12
12
  name = "solentware-base"
13
- version = "5.2.3"
13
+ version = "5.4"
14
14
  authors = [
15
15
  { name="Roger Marsh", email="roger.marsh@solentware.co.uk" },
16
16
  ]
@@ -62,7 +62,7 @@ class Database:
62
62
  """
63
63
  return self._file_per_database
64
64
 
65
- def _generate_database_file_name(self, name):
65
+ def generate_database_file_name(self, name):
66
66
  """Return path to database file.
67
67
 
68
68
  By default this is a file where os.path.basename(path) is same as
@@ -332,7 +332,7 @@ class Database:
332
332
  # record number only.
333
333
  return self.is_primary(file, field)
334
334
 
335
- def repair_cursor(self, oldcursor, *a):
335
+ def repair_cursor(self, oldcursor, file, field):
336
336
  """Return oldcursor for compatibility with DPT database engine.
337
337
 
338
338
  When using the DPT database engine an application may need to replace
@@ -344,10 +344,10 @@ class Database:
344
344
  cursor in DPT. The existing cursor will notice the new record in the
345
345
  Berkeley DB and SQLite3 database engines.
346
346
 
347
- *a absorbs the arguments needed by the DPT version of this method.
347
+ The 'file' and 'field' parameters are ignored.
348
348
 
349
349
  """
350
- del a
350
+ del file, field
351
351
  return oldcursor
352
352
 
353
353
  def allocate_and_open_contexts(self, files=None):
@@ -265,8 +265,14 @@ class Database(_database.Database):
265
265
  self.deferred_update_housekeeping()
266
266
  self.start_transaction()
267
267
 
268
- def next_sorted_item(self, index_directory):
269
- """Yield sorted items from files in index_directory."""
270
- merger = merge.Merge(index_directory)
271
- for item in merger.sorter():
272
- yield item
268
+ def get_merge_import_sort_area(self):
269
+ """Return database directory.
270
+
271
+ The directory containing database is used for sorting by default,
272
+ subclasses should override as required.
273
+
274
+ There is little point in doing so unless the sort area is then on
275
+ a different drive or mount point.
276
+
277
+ """
278
+ return self.home_directory
@@ -34,6 +34,7 @@ from .constants import (
34
34
  CONTROL_FILE,
35
35
  DEFAULT_SEGMENT_SIZE_BYTES,
36
36
  SPECIFICATION_KEY,
37
+ APPLICATION_CONTROL_KEY,
37
38
  SEGMENT_SIZE_BYTES_KEY,
38
39
  SEGMENT_HEADER_LENGTH,
39
40
  FIELDS,
@@ -496,6 +497,9 @@ class Database(_database.Database):
496
497
  repr(self.segment_size_bytes).encode(),
497
498
  txn=self.dbtxn,
498
499
  )
500
+ self.table[CONTROL_FILE].put(
501
+ APPLICATION_CONTROL_KEY, repr({}).encode(), txn=self.dbtxn
502
+ )
499
503
  self.commit()
500
504
  self._dbe = dbe
501
505
 
@@ -1252,6 +1256,111 @@ class Database(_database.Database):
1252
1256
  finally:
1253
1257
  cursor.close()
1254
1258
 
1259
+ # Defined for compatibility with _sqlite module.
1260
+ find_values_ascending = find_values
1261
+
1262
+ def find_values_descending(self, valuespec, file):
1263
+ """Yield index file values in valuespec range in descending order."""
1264
+ cursor = self.table[
1265
+ SUBFILE_DELIMITER.join((file, valuespec.field))
1266
+ ].cursor(txn=self.dbtxn)
1267
+ try:
1268
+ if valuespec.above_value and valuespec.below_value:
1269
+ record = cursor.set_range(valuespec.below_value.encode())
1270
+ if record:
1271
+ if record[0] >= valuespec.below_value.encode():
1272
+ record = cursor.prev_nodup()
1273
+ while record:
1274
+ key = record[0].decode()
1275
+ if key <= valuespec.above_value:
1276
+ break
1277
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1278
+ yield key
1279
+ record = cursor.prev_nodup()
1280
+ elif valuespec.above_value and valuespec.to_value:
1281
+ record = cursor.set_range(valuespec.to_value.encode())
1282
+ if record:
1283
+ if record[0] > valuespec.to_value.encode():
1284
+ record = cursor.prev_nodup()
1285
+ while record:
1286
+ key = record[0].decode()
1287
+ if key <= valuespec.above_value:
1288
+ break
1289
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1290
+ yield key
1291
+ record = cursor.prev_nodup()
1292
+ elif valuespec.from_value and valuespec.to_value:
1293
+ record = cursor.set_range(valuespec.to_value.encode())
1294
+ if record:
1295
+ if record[0] > valuespec.to_value.encode():
1296
+ record = cursor.prev_nodup()
1297
+ while record:
1298
+ key = record[0].decode()
1299
+ if key < valuespec.from_value:
1300
+ break
1301
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1302
+ yield key
1303
+ record = cursor.prev_nodup()
1304
+ elif valuespec.from_value and valuespec.below_value:
1305
+ record = cursor.set_range(valuespec.below_value.encode())
1306
+ if record:
1307
+ if record[0] >= valuespec.below_value.encode():
1308
+ record = cursor.prev_nodup()
1309
+ while record:
1310
+ key = record[0].decode()
1311
+ if key < valuespec.from_value:
1312
+ break
1313
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1314
+ yield key
1315
+ record = cursor.prev_nodup()
1316
+ elif valuespec.above_value:
1317
+ record = cursor.last()
1318
+ while record:
1319
+ key = record[0].decode()
1320
+ if key <= valuespec.above_value:
1321
+ break
1322
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1323
+ yield key
1324
+ record = cursor.prev_nodup()
1325
+ elif valuespec.from_value:
1326
+ record = cursor.last()
1327
+ while record:
1328
+ key = record[0].decode()
1329
+ if key < valuespec.from_value:
1330
+ break
1331
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1332
+ yield key
1333
+ record = cursor.prev_nodup()
1334
+ elif valuespec.to_value:
1335
+ record = cursor.set_range(valuespec.to_value.encode())
1336
+ if record:
1337
+ if record[0] > valuespec.to_value.encode():
1338
+ record = cursor.prev_nodup()
1339
+ while record:
1340
+ key = record[0].decode()
1341
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1342
+ yield key
1343
+ record = cursor.prev_nodup()
1344
+ elif valuespec.below_value:
1345
+ record = cursor.set_range(valuespec.below_value.encode())
1346
+ if record:
1347
+ if record[0] >= valuespec.below_value.encode():
1348
+ record = cursor.prev_nodup()
1349
+ while record:
1350
+ key = record[0].decode()
1351
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1352
+ yield key
1353
+ record = cursor.prev_nodup()
1354
+ else:
1355
+ record = cursor.last()
1356
+ while record:
1357
+ key = record[0].decode()
1358
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1359
+ yield key
1360
+ record = cursor.prev_nodup()
1361
+ finally:
1362
+ cursor.close()
1363
+
1255
1364
  # The bit setting in existence bit map decides if a record is put on the
1256
1365
  # recordset created by the make_recordset_*() methods.
1257
1366
 
@@ -1751,7 +1860,7 @@ class Database(_database.Database):
1751
1860
  finally:
1752
1861
  db.close_database()
1753
1862
 
1754
- def _generate_database_file_name(self, name):
1863
+ def generate_database_file_name(self, name):
1755
1864
  """Extend, return path to Berkeley DB file for name.
1756
1865
 
1757
1866
  Delegate to superclass if all databases are in one file.
@@ -1760,9 +1869,28 @@ class Database(_database.Database):
1760
1869
 
1761
1870
  """
1762
1871
  if not self._file_per_database:
1763
- return super()._generate_database_file_name(name)
1872
+ return super().generate_database_file_name(name)
1764
1873
  return os.path.join(self.home_directory, name)
1765
1874
 
1875
+ def get_application_control(self):
1876
+ """Return dict of application control items."""
1877
+ value = self.table[CONTROL_FILE].get(
1878
+ APPLICATION_CONTROL_KEY,
1879
+ txn=self.dbtxn,
1880
+ )
1881
+ if value is not None:
1882
+ return literal_eval(value.decode())
1883
+ return {}
1884
+
1885
+ def set_application_control(self, appcontrol):
1886
+ """Set dict of application control items."""
1887
+ self.table[CONTROL_FILE].delete(
1888
+ APPLICATION_CONTROL_KEY, txn=self.dbtxn
1889
+ )
1890
+ self.table[CONTROL_FILE].put(
1891
+ APPLICATION_CONTROL_KEY, repr(appcontrol).encode(), txn=self.dbtxn
1892
+ )
1893
+
1766
1894
 
1767
1895
  class Cursor(_cursor.Cursor):
1768
1896
  """Define a cursor on the underlying database engine dbset.
@@ -33,6 +33,7 @@ from .constants import (
33
33
  CONTROL_FILE,
34
34
  DEFAULT_SEGMENT_SIZE_BYTES,
35
35
  SPECIFICATION_KEY,
36
+ APPLICATION_CONTROL_KEY,
36
37
  SEGMENT_SIZE_BYTES_KEY,
37
38
  SEGMENT_HEADER_LENGTH,
38
39
  FIELDS,
@@ -638,6 +639,11 @@ class Database(_database.Database):
638
639
  ]
639
640
  )
640
641
  tcl_tk_call(tuple(command))
642
+ command = [self.table[CONTROL_FILE], "put"]
643
+ if self.dbtxn:
644
+ command.extend(["-txn", self.dbtxn])
645
+ command.extend([APPLICATION_CONTROL_KEY, repr({}).encode()])
646
+ tcl_tk_call(tuple(command))
641
647
  self.commit()
642
648
 
643
649
  def _run_db_archive(self):
@@ -1610,6 +1616,157 @@ class Database(_database.Database):
1610
1616
  finally:
1611
1617
  tcl_tk_call((cursor, "close"))
1612
1618
 
1619
+ # Defined for compatibility with _sqlite module.
1620
+ find_values_ascending = find_values
1621
+
1622
+ def find_values_descending(self, valuespec, file):
1623
+ """Yield index file values in valuespec range in descending order."""
1624
+ command = [
1625
+ self.table[SUBFILE_DELIMITER.join((file, valuespec.field))],
1626
+ "cursor",
1627
+ ]
1628
+ if self.dbtxn:
1629
+ command.extend(["-txn", self.dbtxn])
1630
+ cursor = tcl_tk_call(tuple(command))
1631
+ try:
1632
+ if valuespec.above_value and valuespec.below_value:
1633
+ record = tcl_tk_call(
1634
+ (
1635
+ cursor,
1636
+ "get",
1637
+ "-set_range",
1638
+ valuespec.below_value.encode(),
1639
+ )
1640
+ )
1641
+ if record:
1642
+ if record[0][0] >= valuespec.below_value.encode():
1643
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1644
+ while record:
1645
+ key = record[0][0].decode()
1646
+ if key <= valuespec.above_value:
1647
+ break
1648
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1649
+ yield key
1650
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1651
+ elif valuespec.above_value and valuespec.to_value:
1652
+ record = tcl_tk_call(
1653
+ (
1654
+ cursor,
1655
+ "get",
1656
+ "-set_range",
1657
+ valuespec.to_value.encode(),
1658
+ )
1659
+ )
1660
+ if record:
1661
+ if record[0][0] > valuespec.to_value.encode():
1662
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1663
+ while record:
1664
+ key = record[0][0].decode()
1665
+ if key <= valuespec.above_value:
1666
+ break
1667
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1668
+ yield key
1669
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1670
+ elif valuespec.from_value and valuespec.to_value:
1671
+ record = tcl_tk_call(
1672
+ (
1673
+ cursor,
1674
+ "get",
1675
+ "-set_range",
1676
+ valuespec.to_value.encode(),
1677
+ )
1678
+ )
1679
+ if record:
1680
+ if record[0][0] > valuespec.to_value.encode():
1681
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1682
+ while record:
1683
+ key = record[0][0].decode()
1684
+ if key < valuespec.from_value:
1685
+ break
1686
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1687
+ yield key
1688
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1689
+ elif valuespec.from_value and valuespec.below_value:
1690
+ record = tcl_tk_call(
1691
+ (
1692
+ cursor,
1693
+ "get",
1694
+ "-set_range",
1695
+ valuespec.below_value.encode(),
1696
+ )
1697
+ )
1698
+ if record:
1699
+ if record[0][0] >= valuespec.below_value.encode():
1700
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1701
+ while record:
1702
+ key = record[0][0].decode()
1703
+ if key < valuespec.from_value:
1704
+ break
1705
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1706
+ yield key
1707
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1708
+ elif valuespec.above_value:
1709
+ record = tcl_tk_call((cursor, "get", "-last"))
1710
+ while record:
1711
+ key = record[0][0].decode()
1712
+ if key <= valuespec.above_value:
1713
+ break
1714
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1715
+ yield key
1716
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1717
+ elif valuespec.from_value:
1718
+ record = tcl_tk_call((cursor, "get", "-last"))
1719
+ while record:
1720
+ key = record[0][0].decode()
1721
+ if key < valuespec.from_value:
1722
+ break
1723
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1724
+ yield key
1725
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1726
+ elif valuespec.to_value:
1727
+ record = tcl_tk_call(
1728
+ (
1729
+ cursor,
1730
+ "get",
1731
+ "-set_range",
1732
+ valuespec.to_value.encode(),
1733
+ )
1734
+ )
1735
+ if record:
1736
+ if record[0][0] > valuespec.to_value.encode():
1737
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1738
+ while record:
1739
+ key = record[0][0].decode()
1740
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1741
+ yield key
1742
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1743
+ elif valuespec.below_value:
1744
+ record = tcl_tk_call(
1745
+ (
1746
+ cursor,
1747
+ "get",
1748
+ "-set_range",
1749
+ valuespec.below_value.encode(),
1750
+ )
1751
+ )
1752
+ if record:
1753
+ if record[0][0] >= valuespec.below_value.encode():
1754
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1755
+ while record:
1756
+ key = record[0][0].decode()
1757
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1758
+ yield key
1759
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1760
+ else:
1761
+ record = tcl_tk_call((cursor, "get", "-last"))
1762
+ while record:
1763
+ key = record[0][0].decode()
1764
+ if valuespec.apply_pattern_and_set_filters_to_value(key):
1765
+ yield key
1766
+ record = tcl_tk_call((cursor, "get", "-prevnodup"))
1767
+ finally:
1768
+ tcl_tk_call((cursor, "close"))
1769
+
1613
1770
  # The bit setting in existence bit map decides if a record is put on the
1614
1771
  # recordset created by the make_recordset_*() methods.
1615
1772
 
@@ -2185,7 +2342,7 @@ class Database(_database.Database):
2185
2342
  finally:
2186
2343
  db.close_database()
2187
2344
 
2188
- def _generate_database_file_name(self, name):
2345
+ def generate_database_file_name(self, name):
2189
2346
  """Extend, return path to Berkeley DB file for name.
2190
2347
 
2191
2348
  Delegate to superclass if all databases are in one file.
@@ -2194,9 +2351,37 @@ class Database(_database.Database):
2194
2351
 
2195
2352
  """
2196
2353
  if not self._file_per_database:
2197
- return super()._generate_database_file_name(name)
2354
+ return super().generate_database_file_name(name)
2198
2355
  return os.path.join(self.home_directory, name)
2199
2356
 
2357
+ def get_application_control(self):
2358
+ """Return dict of application control items."""
2359
+ command = [self.table[CONTROL_FILE], "get"]
2360
+ if self.dbtxn:
2361
+ command.extend(["-txn", self.dbtxn])
2362
+ command.extend(
2363
+ [
2364
+ APPLICATION_CONTROL_KEY,
2365
+ ]
2366
+ )
2367
+ value = tcl_tk_call(tuple(command))
2368
+ if value is not None:
2369
+ return literal_eval(value.decode())
2370
+ return {}
2371
+
2372
+ def set_application_control(self, appcontrol):
2373
+ """Set dict of application control items."""
2374
+ command = [self.table[CONTROL_FILE], "delete"]
2375
+ if self.dbtxn:
2376
+ command.extend(["-txn", self.dbtxn])
2377
+ command.extend([APPLICATION_CONTROL_KEY])
2378
+ tcl_tk_call(tuple(command))
2379
+ command = [self.table[CONTROL_FILE], "put"]
2380
+ if self.dbtxn:
2381
+ command.extend(["-txn", self.dbtxn])
2382
+ command.extend([APPLICATION_CONTROL_KEY, repr(appcontrol).encode()])
2383
+ tcl_tk_call(tuple(command))
2384
+
2200
2385
 
2201
2386
  class Cursor(_cursor.Cursor):
2202
2387
  """Define a cursor on the underlying database engine dbset.
@@ -430,9 +430,8 @@ class Database(_databasedu.Database):
430
430
  def merge_writer(self, file, field):
431
431
  """Return a Writer instance for the field index on table file.
432
432
 
433
- Call the write() method with object returned by next_sorted_item
434
- method.
435
-
433
+ Call the Writer.write() method with an object yielded by the
434
+ merge.next_sorted_item() function.
436
435
  """
437
436
 
438
437
  def make_segment_from_high(high, transaction):
@@ -522,9 +522,8 @@ class Database(_databasedu.Database):
522
522
  def merge_writer(self, file, field):
523
523
  """Return a Writer instance for the field index on table file.
524
524
 
525
- Call the write() method with object returned by next_sorted_item
526
- method.
527
-
525
+ Call the Writer.write() method with an object yielded by the
526
+ merge.next_sorted_item() function.
528
527
  """
529
528
 
530
529
  def make_segment_from_high(high, get_segment_value):