solentware-base 5.4__tar.gz → 5.5.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 (80) hide show
  1. {solentware_base-5.4/solentware_base.egg-info → solentware_base-5.5.2}/PKG-INFO +2 -2
  2. {solentware_base-5.4 → solentware_base-5.5.2}/pyproject.toml +2 -2
  3. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/__init__.py +1 -1
  4. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/apsw_database.py +1 -0
  5. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/apswdu_database.py +1 -0
  6. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/berkeleydbdu_database.py +1 -0
  7. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/bsddb3du_database.py +1 -0
  8. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/__init__.py +1 -1
  9. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_database.py +1 -0
  10. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_databasedu.py +19 -11
  11. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_db.py +14 -1
  12. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_db_tkinter.py +28 -11
  13. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_dbdu.py +1 -0
  14. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_dbdu_tkinter.py +1 -0
  15. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_dpt.py +7 -6
  16. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_lmdb.py +22 -11
  17. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_lmdbdu.py +1 -0
  18. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_nosql.py +1 -0
  19. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_nosqldu.py +1 -0
  20. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_sqlite.py +51 -38
  21. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_sqlitedu.py +1 -0
  22. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/bytebit.py +1 -0
  23. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/constants.py +2 -1
  24. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/cursor.py +3 -3
  25. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/filespec.py +1 -0
  26. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/recordsetcursor.py +1 -0
  27. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/segmentsize.py +1 -0
  28. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/tree.py +1 -0
  29. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/db_tkinterdu_database.py +1 -0
  30. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/dpt_database.py +1 -0
  31. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/dptdu_database.py +2 -1
  32. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/dptfastload_database.py +1 -0
  33. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/gnu_database.py +1 -0
  34. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/gnu_module.py +1 -0
  35. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/gnudu_database.py +1 -0
  36. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/lmdbdu_database.py +1 -0
  37. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/modulequery.py +2 -1
  38. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/ndbm_module.py +1 -0
  39. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/ndbmdu_database.py +1 -0
  40. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/sqlite3_database.py +1 -0
  41. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/sqlite3du_database.py +1 -0
  42. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/base_3_to_4.py +1 -0
  43. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/base_3_to_4_db.py +1 -0
  44. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/base_3_to_4_sqlite.py +1 -0
  45. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/berkeleydb_du_splice_fix.py +1 -0
  46. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/create_database.py +1 -1
  47. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/unqlite_database.py +1 -0
  48. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/unqlitedu_database.py +1 -0
  49. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/vedis_database.py +1 -0
  50. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/vedisdu_database.py +1 -0
  51. {solentware_base-5.4 → solentware_base-5.5.2/solentware_base.egg-info}/PKG-INFO +2 -2
  52. {solentware_base-5.4 → solentware_base-5.5.2}/LICENCE +0 -0
  53. {solentware_base-5.4 → solentware_base-5.5.2}/MANIFEST.in +0 -0
  54. {solentware_base-5.4 → solentware_base-5.5.2}/README +0 -0
  55. {solentware_base-5.4 → solentware_base-5.5.2}/setup.cfg +0 -0
  56. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/berkeleydb_database.py +0 -0
  57. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/bsddb3_database.py +0 -0
  58. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/_bytebit.py +0 -0
  59. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/find.py +0 -0
  60. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/findvalues.py +0 -0
  61. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/merge.py +0 -0
  62. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/record.py +0 -0
  63. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/recordset.py +0 -0
  64. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/recordsetbasecursor.py +0 -0
  65. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/sortsequential.py +0 -0
  66. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/where.py +0 -0
  67. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/core/wherevalues.py +0 -0
  68. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/db_tcl.py +0 -0
  69. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/db_tkinter_database.py +0 -0
  70. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/lmdb_database.py +0 -0
  71. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/ndbm_database.py +0 -0
  72. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/__init__.py +0 -0
  73. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/compare_dpt_tape_files.py +0 -0
  74. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/sqlite_table_name_upgrade.py +0 -0
  75. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/traverse_dpt_tape_files.py +0 -0
  76. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base/tools/ui_base_3_to_4.py +0 -0
  77. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base.egg-info/SOURCES.txt +0 -0
  78. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base.egg-info/dependency_links.txt +0 -0
  79. {solentware_base-5.4 → solentware_base-5.5.2}/solentware_base.egg-info/top_level.txt +0 -0
  80. {solentware_base-5.4 → solentware_base-5.5.2}/tox.ini +0 -0
@@ -1,16 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solentware-base
3
- Version: 5.4
3
+ Version: 5.5.2
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
7
7
  Project-URL: Homepage, http://www.solentware.co.uk
8
8
  Project-URL: Repository, https://github.com/RogerMarsh/solentware-base.git
9
9
  Project-URL: Bug Tracker, https://github.com/RogerMarsh/solentware-base/issues
10
- Classifier: Programming Language :: Python :: 3.9
11
10
  Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Topic :: Database
16
16
  Classifier: Intended Audience :: Developers
@@ -10,16 +10,16 @@ line-length = 79
10
10
 
11
11
  [project]
12
12
  name = "solentware-base"
13
- version = "5.4"
13
+ version = "5.5.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
- "Programming Language :: Python :: 3.9",
20
19
  "Programming Language :: Python :: 3.10",
21
20
  "Programming Language :: Python :: 3.11",
22
21
  "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
23
  "Operating System :: OS Independent",
24
24
  "Topic :: Database",
25
25
  "Intended Audience :: Developers",
@@ -4,7 +4,7 @@
4
4
 
5
5
  """Provide an identical interface to several Python database modules.
6
6
 
7
- The supported modules, or packages, are apsw, bsbdb3, dbm, dptdb, ndbm,
7
+ The supported modules, or packages, are apsw, bsbdb3, dbm, dpt_dbms, ndbm,
8
8
  sqlite3, unqlite, and vedis.
9
9
 
10
10
  """
@@ -10,6 +10,7 @@ Prefer to use the apswdu_database module when adding lots of new
10
10
  records. It will be a lot quicker because it defers index updates.
11
11
 
12
12
  """
13
+
13
14
  import apsw
14
15
 
15
16
  from .core import _sqlite
@@ -9,6 +9,7 @@ The apsw_database module provides the database interface.
9
9
  Prefer to use the apsw_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import apsw_database
13
14
  from .core import _sqlitedu
14
15
  from .core import _sqlite
@@ -9,6 +9,7 @@ The berkeleydb_database module provides the database interface.
9
9
  Prefer to use the berkeleydb_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import berkeleydb_database
13
14
  from .core import _dbdu
14
15
  from .core import _db
@@ -9,6 +9,7 @@ The bsddb3_database module provides the database interface.
9
9
  Prefer to use the bsddb3_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import bsddb3_database
13
14
  from .core import _dbdu
14
15
  from .core import _db
@@ -16,6 +16,6 @@ The dbm module for dbm.gnu databases is supported.
16
16
 
17
17
  The ndbm module for ndbm.gnu databases is supported.
18
18
 
19
- The dptdb module for DPT databases is supported.
19
+ The dpt_dbms module for DPT databases is supported.
20
20
 
21
21
  """
@@ -9,6 +9,7 @@ methods. The _dpt module's versions of these methods are too different to
9
9
  justify making _dpt.Database a subclass of _database.Database.
10
10
 
11
11
  """
12
+
12
13
  from .segmentsize import SegmentSize
13
14
  from .find import Find
14
15
  from .where import Where
@@ -9,6 +9,7 @@ deferred updates is so different there is no equivalent separate module for
9
9
  DPT.
10
10
 
11
11
  """
12
+
12
13
  from . import _database
13
14
  from .segmentsize import SegmentSize
14
15
  from .constants import SECONDARY
@@ -249,17 +250,24 @@ class Database(_database.Database):
249
250
  writer = self.merge_writer(file, field)
250
251
  merger = merge.Merge(index_directory)
251
252
  commit_count = None
252
- for commit_count, item in enumerate(merger.sorter()):
253
- if not commit_count % commit_limit:
254
- if commit_count:
255
- writer.close_cursor()
256
- self.commit()
257
- self.deferred_update_housekeeping()
258
- yield commit_count
259
- self.start_transaction()
260
- writer.make_new_cursor()
261
- writer.write(item)
262
- writer.close_cursor()
253
+ try:
254
+ for commit_count, item in enumerate(merger.sorter()):
255
+ if not commit_count % commit_limit:
256
+ if commit_count:
257
+ writer.close_cursor()
258
+ self.commit()
259
+ self.deferred_update_housekeeping()
260
+ yield commit_count
261
+ self.start_transaction()
262
+ writer.make_new_cursor()
263
+ writer.write(item)
264
+ writer.close_cursor()
265
+ finally:
266
+ # An exception may leave some reader files open.
267
+ # A 'ResourceWarning: unclosed file <io.TextIOWrapper ...>'
268
+ # message in *_merge_import tests revealed this.
269
+ for reader in merger.readers.values():
270
+ reader.file.close()
263
271
  if commit_count is not None:
264
272
  self.commit()
265
273
  self.deferred_update_housekeeping()
@@ -18,6 +18,7 @@ Berkeley DB 4.6 is not compatible with berkeleydb, but can be accessed by
18
18
  the _db_tkinter module, a sibling of _db (this module).
19
19
 
20
20
  """
21
+
21
22
  import os
22
23
  from ast import literal_eval
23
24
  import bisect
@@ -310,8 +311,10 @@ class Database(_database.Database):
310
311
  self.dbenv.log_set_config(dbe.DB_LOG_AUTO_REMOVE, 1)
311
312
  except AttributeError as exc:
312
313
  if not _openbsd_platform:
314
+ self.dbenv.close()
313
315
  raise
314
316
  if "'log_set_config'" not in str(exc):
317
+ self.dbenv.close()
315
318
  raise
316
319
  if gbytes or bytes_:
317
320
  self.dbenv.set_cachesize(gbytes, bytes_)
@@ -399,6 +402,7 @@ class Database(_database.Database):
399
402
  )
400
403
  except:
401
404
  self.table[CONTROL_FILE] = None
405
+ self.dbenv.close()
402
406
  raise
403
407
  for file, specification in self.specification.items():
404
408
  if file not in files:
@@ -415,6 +419,7 @@ class Database(_database.Database):
415
419
  )
416
420
  except:
417
421
  self.table[file] = None
422
+ self.dbenv.close()
418
423
  raise
419
424
  self.ebm_control[file] = ExistenceBitmapControl(
420
425
  file, self, dbe, db_create
@@ -431,6 +436,7 @@ class Database(_database.Database):
431
436
  )
432
437
  except:
433
438
  self.segment_table[file] = None
439
+ self.dbenv.close()
434
440
  raise
435
441
  fieldprops = specification[FIELDS]
436
442
  for field, fieldname in fields.items():
@@ -463,8 +469,10 @@ class Database(_database.Database):
463
469
  ": unexpected file type or format')",
464
470
  )
465
471
  ):
472
+ self.dbenv.close()
466
473
  raise
467
474
  if access_method is not dbe.DB_HASH:
475
+ self.dbenv.close()
468
476
  raise
469
477
 
470
478
  # Accept existing DB_BTREE database if DB_HASH was in the
@@ -481,10 +489,12 @@ class Database(_database.Database):
481
489
  )
482
490
  except:
483
491
  self.table[secondary] = None
492
+ self.dbenv.close()
484
493
  raise
485
494
 
486
495
  except:
487
496
  self.table[secondary] = None
497
+ self.dbenv.close()
488
498
  raise
489
499
  if db_create: # and files:
490
500
  self.table[CONTROL_FILE].put(
@@ -1038,7 +1048,10 @@ class Database(_database.Database):
1038
1048
  recnums = self._get_segment_record_numbers(file, segment_key)
1039
1049
  if isinstance(recnums, list):
1040
1050
  discard = bisect.bisect_left(recnums, record_number)
1041
- if recnums[discard] == record_number:
1051
+ if (
1052
+ discard < len(recnums)
1053
+ and recnums[discard] == record_number
1054
+ ):
1042
1055
  del recnums[discard]
1043
1056
  count = len(recnums)
1044
1057
  if count < 2:
@@ -15,6 +15,7 @@ In particular on OpenBSD 7.3 where the default Python is 3.10 and 4.6.21
15
15
  is the version of Berkeley DB.
16
16
 
17
17
  """
18
+
18
19
  import os
19
20
  from ast import literal_eval
20
21
  import bisect
@@ -332,16 +333,20 @@ class Database(_database.Database):
332
333
  1
333
334
  ].decode()
334
335
  )
335
- if self._use_specification_items is not None:
336
- self.specification.is_consistent_with(
337
- {
338
- k: v
339
- for k, v in spec_from_db.items()
340
- if k in self._use_specification_items
341
- }
342
- )
343
- else:
344
- self.specification.is_consistent_with(spec_from_db)
336
+ try:
337
+ if self._use_specification_items is not None:
338
+ self.specification.is_consistent_with(
339
+ {
340
+ k: v
341
+ for k, v in spec_from_db.items()
342
+ if k in self._use_specification_items
343
+ }
344
+ )
345
+ else:
346
+ self.specification.is_consistent_with(spec_from_db)
347
+ except:
348
+ tcl_tk_call((self.dbenv, "close"))
349
+ raise
345
350
  segment_size = literal_eval(
346
351
  tcl_tk_call((control, "get", SEGMENT_SIZE_BYTES_KEY))[0][
347
352
  1
@@ -352,6 +357,7 @@ class Database(_database.Database):
352
357
  self._real_segment_size_bytes = False
353
358
  if segment_size != self.segment_size_bytes:
354
359
  self._real_segment_size_bytes = segment_size
360
+ tcl_tk_call((self.dbenv, "close"))
355
361
  raise self.SegmentSizeError(
356
362
  "".join(
357
363
  (
@@ -368,6 +374,7 @@ class Database(_database.Database):
368
374
  # Assume equivalent to not a DBNoSuchFileError exception if path
369
375
  # exists.
370
376
  if fnfd and os.path.exists(fnfd):
377
+ tcl_tk_call((self.dbenv, "close"))
371
378
  raise
372
379
  db_create = True
373
380
  options = ["-create"]
@@ -492,6 +499,7 @@ class Database(_database.Database):
492
499
  self.table[CONTROL_FILE] = tcl_tk_call(tuple(command))
493
500
  except TclError:
494
501
  self.table[CONTROL_FILE] = None
502
+ tcl_tk_call((self.dbenv, "close"))
495
503
  raise
496
504
  for file, specification in self.specification.items():
497
505
  if file not in files:
@@ -520,6 +528,7 @@ class Database(_database.Database):
520
528
  self.table[file] = tcl_tk_call(tuple(command))
521
529
  except TclError:
522
530
  self.table[file] = None
531
+ tcl_tk_call((self.dbenv, "close"))
523
532
  raise
524
533
  self.ebm_control[file] = ExistenceBitmapControl(
525
534
  file, self, dbe, db_create
@@ -547,6 +556,7 @@ class Database(_database.Database):
547
556
  self.segment_table[file] = tcl_tk_call(tuple(command))
548
557
  except TclError:
549
558
  self.segment_table[file] = None
559
+ tcl_tk_call((self.dbenv, "close"))
550
560
  raise
551
561
  fieldprops = specification[FIELDS]
552
562
  for field, fieldname in fields.items():
@@ -593,8 +603,10 @@ class Database(_database.Database):
593
603
  )
594
604
  )
595
605
  ):
606
+ tcl_tk_call((self.dbenv, "close"))
596
607
  raise
597
608
  if access_method != "-hash":
609
+ tcl_tk_call((self.dbenv, "close"))
598
610
  raise
599
611
 
600
612
  # Accept existing DB_BTREE database if DB_HASH was in the
@@ -616,10 +628,12 @@ class Database(_database.Database):
616
628
  self.table[secondary] = tcl_tk_call(tuple(command))
617
629
  except:
618
630
  self.table[secondary] = None
631
+ tcl_tk_call((self.dbenv, "close"))
619
632
  raise
620
633
 
621
634
  except:
622
635
  self.table[secondary] = None
636
+ tcl_tk_call((self.dbenv, "close"))
623
637
  raise
624
638
  if db_create: # and files:
625
639
  command = [self.table[CONTROL_FILE], "put"]
@@ -1323,7 +1337,10 @@ class Database(_database.Database):
1323
1337
  recnums = self._get_segment_record_numbers(file, segment_key)
1324
1338
  if isinstance(recnums, list):
1325
1339
  discard = bisect.bisect_left(recnums, record_number)
1326
- if recnums[discard] == record_number:
1340
+ if (
1341
+ discard < len(recnums)
1342
+ and recnums[discard] == record_number
1343
+ ):
1327
1344
  del recnums[discard]
1328
1345
  count = len(recnums)
1329
1346
  if count < 2:
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Access a Berkeley DB database with the berkeleydb or bsddb3 modules."""
6
+
6
7
  from .constants import (
7
8
  SECONDARY,
8
9
  # ACCESS_METHOD,
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Access a Berkeley DB database with tcl via the tkinter module."""
6
+
6
7
  from ..db_tcl import tcl_tk_call
7
8
  from .constants import (
8
9
  SECONDARY,
@@ -2,17 +2,18 @@
2
2
  # Copyright 2019 Roger Marsh
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
- """Access a DPT database with the dptdb module.
5
+ """Access a DPT database with the dpt_dbms module.
6
6
 
7
7
  The database will have been created from the application's customization
8
8
  of the filespec.FileSpec class.
9
9
 
10
10
  """
11
+
11
12
  import os
12
13
  from ast import literal_eval
13
14
  import re
14
15
 
15
- from dptdb import dptapi
16
+ from dpt_dbms import dptapi
16
17
 
17
18
  from . import _database
18
19
  from . import filespec
@@ -420,7 +421,7 @@ class Database(_database.Database):
420
421
  return self.table[file].get_primary_record(key)
421
422
 
422
423
  def encode_record_number(self, key):
423
- """Return repr(key) because this is dptdb version.
424
+ """Return repr(key) because this is dpt_dbms version.
424
425
 
425
426
  Typically used to convert primary key, a record number, to secondary
426
427
  index format.
@@ -429,7 +430,7 @@ class Database(_database.Database):
429
430
  return repr(key)
430
431
 
431
432
  def decode_record_number(self, skey):
432
- """Return literal_eval(skey) because this is dptdb version.
433
+ """Return literal_eval(skey) because this is dpt_dbms version.
433
434
 
434
435
  Typically used to convert secondary index reference to primary record,
435
436
  a str(int), to a record number.
@@ -438,7 +439,7 @@ class Database(_database.Database):
438
439
  return literal_eval(skey)
439
440
 
440
441
  def encode_record_selector(self, key):
441
- """Return key because this is dptdb version.
442
+ """Return key because this is dpt_dbms version.
442
443
 
443
444
  Typically used to convert a key being used to search a secondary index
444
445
  to the form held on the database.
@@ -818,7 +819,7 @@ class Database(_database.Database):
818
819
  yield value
819
820
  dvcursor.Advance()
820
821
  else:
821
- dvcursor.GotoLast()
822
+ dvcursor.GotoFirst()
822
823
  while dvcursor.Accessible():
823
824
  value = dvcursor.GetCurrentValue().ExtractString()
824
825
  if valuespec.apply_pattern_and_set_filters_to_value(value):
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Access a Symas Lightning Memory-Mapped Database (LMMD) database."""
6
+
6
7
  import os
7
8
  from ast import literal_eval
8
9
  import bisect
@@ -275,6 +276,7 @@ class Database(_database.Database):
275
276
  )
276
277
  except:
277
278
  self.table[DESIGN_FILE] = None
279
+ dbenv.close()
278
280
  raise
279
281
  try:
280
282
  self.table[CONTROL_FILE] = _Datastore(
@@ -284,6 +286,7 @@ class Database(_database.Database):
284
286
  )
285
287
  except:
286
288
  self.table[CONTROL_FILE] = None
289
+ dbenv.close()
287
290
  raise
288
291
  if files is None:
289
292
  files = self.specification.keys()
@@ -309,6 +312,7 @@ class Database(_database.Database):
309
312
  )
310
313
  except:
311
314
  self.segment_table[file] = None
315
+ dbenv.close()
312
316
  raise
313
317
  for field, fieldname in fields.items():
314
318
  if fieldname is None:
@@ -373,16 +377,20 @@ class Database(_database.Database):
373
377
  self.end_read_only_transaction()
374
378
  self.table[DESIGN_FILE].close_datastore()
375
379
  spec_from_db = literal_eval(spec_from_db.decode())
376
- if self._use_specification_items is not None:
377
- self.specification.is_consistent_with(
378
- {
379
- k: v
380
- for k, v in spec_from_db.items()
381
- if k in self._use_specification_items
382
- }
383
- )
384
- else:
385
- self.specification.is_consistent_with(spec_from_db)
380
+ try:
381
+ if self._use_specification_items is not None:
382
+ self.specification.is_consistent_with(
383
+ {
384
+ k: v
385
+ for k, v in spec_from_db.items()
386
+ if k in self._use_specification_items
387
+ }
388
+ )
389
+ else:
390
+ self.specification.is_consistent_with(spec_from_db)
391
+ except:
392
+ self.dbenv.close()
393
+ raise
386
394
  segment_size = literal_eval(segment_size.decode())
387
395
  if self._real_segment_size_bytes is not False:
388
396
  self.segment_size_bytes = self._real_segment_size_bytes
@@ -1108,7 +1116,10 @@ class Database(_database.Database):
1108
1116
  recnums = self._get_segment_record_numbers(file, segment_key)
1109
1117
  if isinstance(recnums, list):
1110
1118
  discard = bisect.bisect_left(recnums, record_number)
1111
- if recnums[discard] == record_number:
1119
+ if (
1120
+ discard < len(recnums)
1121
+ and recnums[discard] == record_number
1122
+ ):
1112
1123
  del recnums[discard]
1113
1124
  count = len(recnums)
1114
1125
  if count < 2:
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Deferred update access to Symas Lightning Memory-Mapped Database (LMMD)."""
6
+
6
7
  from .constants import (
7
8
  SECONDARY,
8
9
  SUBFILE_DELIMITER,
@@ -9,6 +9,7 @@ interfaces are sufficiently similar that one module and set of classes
9
9
  can cope with all of them.
10
10
 
11
11
  """
12
+
12
13
  import os
13
14
  from ast import literal_eval
14
15
  import re
@@ -10,6 +10,7 @@ The dbm and ndbm modules are provided with Python; the unqlite and vedis
10
10
  modules can be found in PyPI.
11
11
 
12
12
  """
13
+
13
14
  from ast import literal_eval
14
15
  from bisect import bisect_right
15
16
 
@@ -7,6 +7,7 @@
7
7
  When using sqlite3 the Python version must be 3.6 or later.
8
8
 
9
9
  """
10
+
10
11
  import os
11
12
  from ast import literal_eval
12
13
  import re
@@ -172,45 +173,64 @@ class Database(_database.Database):
172
173
  if self.database_file is not None:
173
174
  dbenv = dbe.Connection(self.database_file)
174
175
  cursor = dbenv.cursor()
175
- statement = " ".join(
176
- (
177
- "select",
178
- SQLITE_VALUE_COLUMN,
179
- "from",
180
- CONTROL_FILE,
181
- "where",
182
- CONTROL_FILE,
183
- "== ?",
184
- )
176
+ cursor.execute(
177
+ " ".join(
178
+ (
179
+ "select name from sqlite_master",
180
+ "where type == 'table' and name == ?",
181
+ )
182
+ ),
183
+ (CONTROL_FILE,),
185
184
  )
186
- try:
185
+ if cursor.fetchall():
186
+ statement = " ".join(
187
+ (
188
+ "select",
189
+ SQLITE_VALUE_COLUMN,
190
+ "from",
191
+ CONTROL_FILE,
192
+ "where",
193
+ CONTROL_FILE,
194
+ "== ?",
195
+ )
196
+ )
187
197
  cursor.execute(statement, (SPECIFICATION_KEY,))
188
198
  rsk = cursor.fetchall()
189
- except Exception:
190
- pass
191
- try:
192
199
  cursor.execute(statement, (SEGMENT_SIZE_BYTES_KEY,))
193
200
  rssbk = cursor.fetchall()
194
- except Exception:
195
- pass
196
201
  if rsk is not None and rssbk is not None:
197
202
  spec_from_db = literal_eval(rsk[0][0])
198
- if self._use_specification_items is not None:
199
- self.specification.is_consistent_with(
200
- {
201
- k: v
202
- for k, v in spec_from_db.items()
203
- if k in self._use_specification_items
204
- }
205
- )
206
- else:
207
- self.specification.is_consistent_with(spec_from_db)
203
+
204
+ # This 'try ... except ...' prevents 7 of the 16 ERROR reports
205
+ # produced, ignoring tests in test___do_database_tasks, on
206
+ # Microsoft Windows when run by
207
+ # 'py -3.13 -m unittest -k test_deferred_update'.
208
+ # The expected exception is FileSpecError but catch all to stay
209
+ # as close as possible to original code.
210
+ try:
211
+ if self._use_specification_items is not None:
212
+ self.specification.is_consistent_with(
213
+ {
214
+ k: v
215
+ for k, v in spec_from_db.items()
216
+ if k in self._use_specification_items
217
+ }
218
+ )
219
+ else:
220
+ self.specification.is_consistent_with(spec_from_db)
221
+ except:
222
+ cursor.close()
223
+ dbenv.close()
224
+ raise
225
+
208
226
  segment_size = literal_eval(rssbk[0][0])
209
227
  if self._real_segment_size_bytes is not False:
210
228
  self.segment_size_bytes = self._real_segment_size_bytes
211
229
  self._real_segment_size_bytes = False
212
230
  if segment_size != self.segment_size_bytes:
213
231
  self._real_segment_size_bytes = segment_size
232
+ cursor.close()
233
+ dbenv.close()
214
234
  raise self.SegmentSizeError(
215
235
  "".join(
216
236
  (
@@ -220,8 +240,12 @@ class Database(_database.Database):
220
240
  )
221
241
  )
222
242
  elif rsk is None and rssbk is not None:
243
+ cursor.close()
244
+ dbenv.close()
223
245
  raise DatabaseError("No specification recorded in database")
224
246
  elif rsk is not None and rssbk is None:
247
+ cursor.close()
248
+ dbenv.close()
225
249
  raise DatabaseError("No segment size recorded in database")
226
250
  else:
227
251
  dbenv = dbe.Connection(":memory:")
@@ -1942,18 +1966,7 @@ class Database(_database.Database):
1942
1966
  "glob ?",
1943
1967
  )
1944
1968
  )
1945
- values = (
1946
- b"".join(
1947
- (
1948
- (
1949
- keystart.encode()
1950
- if isinstance(keystart, str)
1951
- else keystart
1952
- ),
1953
- b"*",
1954
- )
1955
- ),
1956
- )
1969
+ values = (keystart + "*",)
1957
1970
  db_segment_size_bytes = SegmentSize.db_segment_size_bytes
1958
1971
  get_segment_records = self.get_segment_records
1959
1972
  cursor = self.dbenv.cursor()
@@ -7,6 +7,7 @@
7
7
  When using sqlite3 the Python version must be 3.6 or later.
8
8
 
9
9
  """
10
+
10
11
  from .constants import (
11
12
  SECONDARY,
12
13
  SQLITE_SEGMENT_COLUMN,
@@ -14,6 +14,7 @@ Bitarray mostly takes about 4 times longer to do something than bitarray, but
14
14
  takes about 100 times longer to count set bits.
15
15
 
16
16
  """
17
+
17
18
  # The decision is made here, rather than in solentware_base.__init__, because
18
19
  # the DPT specific modules in solentware_base do not need a bit array class as
19
20
  # DPT provides it's own bit array handling.
@@ -10,10 +10,11 @@ See www.dptoolkit.com for details of DPT (No longer exists. The database
10
10
  interface part of DPT is available at www.solentware.co.uk)
11
11
 
12
12
  """
13
+
13
14
  # Module names of supported database engines (<module>.__name__).
14
15
  BERKELEYDB_MODULE = "berkeleydb"
15
16
  BSDDB3_MODULE = "bsddb3"
16
- DPT_MODULE = "dptdb.dptapi"
17
+ DPT_MODULE = "dpt_dbms.dptapi"
17
18
  SQLITE3_MODULE = "sqlite3"
18
19
  APSW_MODULE = "apsw"
19
20
  UNQLITE_MODULE = "unqlite"
@@ -31,9 +31,9 @@ class Cursor:
31
31
 
32
32
  For apsw and sqlite3 (SQLite) dbset will be a Connection() object.
33
33
 
34
- For dptdb (DPT) dbset will be a core._dpt.DPTFile() object which creates
35
- a RecordSetCursor() or DirectValueCursor(), for records and indicies, on
36
- an OpenContext() object.
34
+ For dpt_dbms (DPT) dbset will be a core._dpt.DPTFile() object which
35
+ creates a RecordSetCursor() or DirectValueCursor(), for records and
36
+ indicies, on an OpenContext() object.
37
37
 
38
38
  (A version of the DPT interface is planned where dbset will be an
39
39
  OpenContext() object.)
@@ -7,6 +7,7 @@
7
7
  Example database specifications are in the samples directory.
8
8
 
9
9
  """
10
+
10
11
  import os
11
12
 
12
13
  from .constants import (
@@ -8,6 +8,7 @@ Method names are taken from Berkeley DB to indicate preference for that
8
8
  style of cursor.
9
9
 
10
10
  """
11
+
11
12
  from . import cursor
12
13
 
13
14
 
@@ -28,6 +28,7 @@ Normalization converts a list with more than 'upper' records to a bitmap.
28
28
  Normalization converts a bitmap with less than 'lower' records to a list.
29
29
 
30
30
  """
31
+
31
32
  from . import bytebit
32
33
 
33
34
 
@@ -8,6 +8,7 @@ This module provides ordered access to indicies stored in databases such as
8
8
  UnQLite and Vedis.
9
9
 
10
10
  """
11
+
11
12
  from bisect import bisect_right, bisect_left
12
13
  from ast import literal_eval
13
14
 
@@ -9,6 +9,7 @@ The db_tkinter_database module provides the database interface.
9
9
  Prefer to use the tkinter_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import db_tkinter_database
13
14
  from .core import _dbdu_tkinter
14
15
  from .core import _db_tkinter
@@ -9,6 +9,7 @@ updates, which will be a lot quicker when adding lots of new
9
9
  records.
10
10
 
11
11
  """
12
+
12
13
  from .core import _dpt
13
14
 
14
15
 
@@ -9,9 +9,10 @@ external backups should be used. Use dpt_database for transactions,
9
9
  but adding lots of new records will be a lot slower.
10
10
 
11
11
  """
12
+
12
13
  import os
13
14
 
14
- from dptdb import dptapi
15
+ from dpt_dbms import dptapi
15
16
 
16
17
  from .core import _dpt
17
18
  from .core.constants import (
@@ -8,6 +8,7 @@ The DPT fastload interface is used to do updates. The compressed file
8
8
  format defined in Appendix 2 of the DBA Guide is used.
9
9
 
10
10
  """
11
+
11
12
  import os
12
13
 
13
14
  from .core import _dpt
@@ -10,6 +10,7 @@ Prefer to use the gnudu_database module when adding lots of new
10
10
  records. It will be a lot quicker because it defers index updates.
11
11
 
12
12
  """
13
+
13
14
  from . import gnu_module
14
15
  from .core import _nosql
15
16
 
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Provide Gnu class to fit dbm.gnu API to UnQLite and Vedis API."""
6
+
6
7
  import dbm.gnu
7
8
 
8
9
 
@@ -9,6 +9,7 @@ The gnu_database module provides the database interface.
9
9
  Prefer to use the gnu_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import gnu_database
13
14
  from .core import _nosqldu
14
15
  from .core import _nosql
@@ -7,6 +7,7 @@
7
7
  The lmdb_database module provides the database interface.
8
8
 
9
9
  """
10
+
10
11
  from . import lmdb_database
11
12
  from .core import _lmdbdu
12
13
  from .core import _lmdb
@@ -49,6 +49,7 @@ Berkeley DB (db) is made available via tkinter if the tcl interface to db
49
49
  is configured in the installed db.
50
50
 
51
51
  """
52
+
52
53
  import sys
53
54
  import os
54
55
 
@@ -123,7 +124,7 @@ try:
123
124
  except ImportError: # Not ModuleNotFoundError for Pythons earlier than 3.6
124
125
  lmdb = None
125
126
  try:
126
- from dptdb import dptapi
127
+ from dpt_dbms import dptapi
127
128
  except ImportError: # Not ModuleNotFoundError for Pythons earlier than 3.6
128
129
  dptapi = None
129
130
  if _allow("allow_ndbm") or _allow("-n"):
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Provide Ndbm class to fit dbm.ndbm API to UnQLite and Vedis API."""
6
+
6
7
  import dbm.ndbm
7
8
 
8
9
 
@@ -9,6 +9,7 @@ The ndbm_database module provides the database interface.
9
9
  Prefer to use the ndbm_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import ndbm_database
13
14
  from .core import _nosqldu
14
15
  from .core import _nosql
@@ -13,6 +13,7 @@ The Python version must be 3.6 or later. Use apsw_database on earlier
13
13
  versions of Python.
14
14
 
15
15
  """
16
+
16
17
  import sqlite3
17
18
 
18
19
  from .core import _sqlite
@@ -9,6 +9,7 @@ The sqlite3_database module provides the database interface.
9
9
  Prefer to use the sqlite3_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import sqlite3_database
13
14
  from .core import _sqlitedu
14
15
  from .core import _sqlite
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Upgrade a solentware_base version 3 database to version 4."""
6
+
6
7
  import os
7
8
 
8
9
  from ..core.filespec import FileSpec
@@ -8,6 +8,7 @@ The Berkeley DB databases are moved from their 'one database per file'
8
8
  organization to an 'all databases on one file' organization.
9
9
 
10
10
  """
11
+
11
12
  import os
12
13
 
13
14
  from ..core.segmentsize import SegmentSize
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENCE (BSD licence)
4
4
 
5
5
  """Upgrade a solentware_base version 3 database on SQLite 3 to version 4."""
6
+
6
7
  import os
7
8
 
8
9
  from ..core.segmentsize import SegmentSize
@@ -3,6 +3,7 @@
3
3
  # Licence: See LICENSE.txt (BSD licence)
4
4
 
5
5
  """Delete index references kept, not replaced, in deferred update runs."""
6
+
6
7
  import os
7
8
  import sys
8
9
 
@@ -61,7 +61,7 @@ try:
61
61
  except ImportError: # Not ModuleNotFoundError for Pythons earlier than 3.6
62
62
  db_tcl = None
63
63
  try:
64
- from dptdb import dptapi
64
+ from dpt_dbms import dptapi
65
65
  except ImportError: # Not ModuleNotFoundError for Pythons earlier than 3.6
66
66
  dptapi = None
67
67
  try:
@@ -10,6 +10,7 @@ Prefer to use the unqlitedu_database module when adding lots of new
10
10
  records. It will be a lot quicker because it defers index updates.
11
11
 
12
12
  """
13
+
13
14
  import unqlite
14
15
 
15
16
  from .core import _nosql
@@ -9,6 +9,7 @@ The unqlite_database module provides the database interface.
9
9
  Prefer to use the unqlite_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import unqlite_database
13
14
  from .core import _nosqldu
14
15
  from .core import _nosql
@@ -10,6 +10,7 @@ Prefer to use the vedisdu_database module when adding lots of new
10
10
  records. It will be a lot quicker because it defers index updates.
11
11
 
12
12
  """
13
+
13
14
  import vedis
14
15
 
15
16
  from .core import _nosql
@@ -9,6 +9,7 @@ The vedis_database module provides the database interface.
9
9
  Prefer to use the vedis_database module normally.
10
10
 
11
11
  """
12
+
12
13
  from . import vedis_database
13
14
  from .core import _nosqldu
14
15
  from .core import _nosql
@@ -1,16 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solentware-base
3
- Version: 5.4
3
+ Version: 5.5.2
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
7
7
  Project-URL: Homepage, http://www.solentware.co.uk
8
8
  Project-URL: Repository, https://github.com/RogerMarsh/solentware-base.git
9
9
  Project-URL: Bug Tracker, https://github.com/RogerMarsh/solentware-base/issues
10
- Classifier: Programming Language :: Python :: 3.9
11
10
  Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Topic :: Database
16
16
  Classifier: Intended Audience :: Developers
File without changes
File without changes
File without changes
File without changes