apsw-sqlite3mc 3.53.2.0__tar.gz → 3.53.3.1__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 (75) hide show
  1. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/PKG-INFO +2 -2
  2. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/README.rst +1 -1
  3. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/__init__.pyi +23 -9
  4. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/sqlite_extra.json +0 -4
  5. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/__main__.py +53 -22
  6. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/aiotest.py +11 -3
  7. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/extratest.py +3 -0
  8. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/ftstests.py +8 -0
  9. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/mctests.py +6 -1
  10. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw_sqlite3mc.egg-info/PKG-INFO +2 -2
  11. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/checksums +3 -1
  12. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/setup.py +7 -3
  13. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/sqlite3/sqlite3.c +521 -282
  14. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/apsw.c +76 -21
  15. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/apsw.docstrings +9 -2
  16. apsw_sqlite3mc-3.53.3.1/src/apswversion.h +1 -0
  17. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/connection.c +50 -11
  18. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/sqlite_debug.h +20 -0
  19. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/tools/vend.py +0 -4
  20. apsw_sqlite3mc-3.53.2.0/src/apswversion.h +0 -1
  21. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/LICENSE +0 -0
  22. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/MANIFEST.in +0 -0
  23. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/__main__.py +0 -0
  24. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/aio.py +0 -0
  25. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/bestpractice.py +0 -0
  26. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/ext.py +0 -0
  27. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/fts5.py +0 -0
  28. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/fts5aux.py +0 -0
  29. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/fts5query.py +0 -0
  30. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/fts_test_strings +0 -0
  31. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/mcall.py +0 -0
  32. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/py.typed +0 -0
  33. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/shell.py +0 -0
  34. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/speedtest.py +0 -0
  35. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/sqlite_extra.py +0 -0
  36. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/sqlite_extra_binaries/README.md +0 -0
  37. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/async_meta.py +0 -0
  38. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/carray.py +0 -0
  39. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/fork_checker.py +0 -0
  40. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/jsonb.py +0 -0
  41. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/sessiontests.py +0 -0
  42. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/tests/shelltest.py +0 -0
  43. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/trace.py +0 -0
  44. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw/unicode.py +0 -0
  45. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw_sqlite3mc.egg-info/SOURCES.txt +0 -0
  46. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw_sqlite3mc.egg-info/dependency_links.txt +0 -0
  47. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw_sqlite3mc.egg-info/entry_points.txt +0 -0
  48. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/apsw_sqlite3mc.egg-info/top_level.txt +0 -0
  49. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/pyproject.toml +0 -0
  50. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/setup.apsw +0 -0
  51. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/setup.cfg +0 -0
  52. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/_unicodedb.c +0 -0
  53. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/argparse.c +0 -0
  54. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/async.c +0 -0
  55. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/backup.c +0 -0
  56. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/blob.c +0 -0
  57. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/carray.c +0 -0
  58. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/constants.c +0 -0
  59. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/cursor.c +0 -0
  60. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/exceptions.c +0 -0
  61. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/faultinject.c +0 -0
  62. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/faultinject.h +0 -0
  63. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/fileio_win32.c +0 -0
  64. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/fts.c +0 -0
  65. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/jsonb.c +0 -0
  66. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/pyutil.c +0 -0
  67. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/session.c +0 -0
  68. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/statementcache.c +0 -0
  69. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/stringconstants.c +0 -0
  70. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/testextension.c +0 -0
  71. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/traceback.c +0 -0
  72. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/unicode.c +0 -0
  73. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/util.c +0 -0
  74. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/vfs.c +0 -0
  75. {apsw_sqlite3mc-3.53.2.0 → apsw_sqlite3mc-3.53.3.1}/src/vtable.c +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apsw_sqlite3mc
3
- Version: 3.53.2.0
3
+ Version: 3.53.3.1
4
4
  Summary: SQLite3 Multiple Ciphers combined with Another Python SQLite Wrapper
5
5
  Home-page: https://github.com/utelle/apsw-sqlite3mc
6
6
  Author: Ulrich Telle
@@ -90,7 +90,7 @@ Setting the key on a new database is the only change needed to your code.
90
90
 
91
91
  >>> import apsw
92
92
  >>> print(apsw.mc_version)
93
- SQLite3 Multiple Ciphers 2.3.5
93
+ SQLite3 Multiple Ciphers 2.3.6
94
94
  >>> con = apsw.Connection("database.sqlite3")
95
95
  >>> con.pragma("key", "my secret passphrase")
96
96
  ok
@@ -59,7 +59,7 @@ Setting the key on a new database is the only change needed to your code.
59
59
 
60
60
  >>> import apsw
61
61
  >>> print(apsw.mc_version)
62
- SQLite3 Multiple Ciphers 2.3.5
62
+ SQLite3 Multiple Ciphers 2.3.6
63
63
  >>> con = apsw.Connection("database.sqlite3")
64
64
  >>> con.pragma("key", "my secret passphrase")
65
65
  ok
@@ -1748,7 +1748,9 @@ class Connection:
1748
1748
  """If *keep* is *None* then all registered virtual tables are dropped.
1749
1749
 
1750
1750
  Otherwise *keep* is a sequence of strings, naming the virtual tables that
1751
- are kept, dropping all others."""
1751
+ are kept, dropping all others.
1752
+
1753
+ Calls: `sqlite3_drop_modules <https://sqlite.org/c3ref/drop_modules.html>`__"""
1752
1754
  ...
1753
1755
 
1754
1756
  def enable_load_extension(self, enable: bool) -> None:
@@ -1926,7 +1928,9 @@ class Connection:
1926
1928
  ...
1927
1929
 
1928
1930
  def get_autocommit(self) -> bool:
1929
- """Returns if the Connection is in auto commit mode (ie not in a transaction).
1931
+ """Returns if the Connection is in auto commit mode (ie not in a
1932
+ transaction). It is recommended to use :meth:`txn_state` instead
1933
+ which is more reliable.
1930
1934
 
1931
1935
  Calls: `sqlite3_get_autocommit <https://sqlite.org/c3ref/get_autocommit.html>`__"""
1932
1936
  ...
@@ -1993,6 +1997,9 @@ class Connection:
1993
1997
 
1994
1998
  def last_insert_rowid(self) -> int:
1995
1999
  """Returns the integer key of the most recent insert in the database.
2000
+ It is recommended to use SQL `RETURNING <https://sqlite.org/lang_returning.html>`__
2001
+ instead because that ensures you get the rowid directly from the
2002
+ SQL that made the change.
1996
2003
 
1997
2004
  Calls: `sqlite3_last_insert_rowid <https://sqlite.org/c3ref/last_insert_rowid.html>`__"""
1998
2005
  ...
@@ -6354,7 +6361,7 @@ class AsyncConnection:
6354
6361
  the first statement"""
6355
6362
  ...
6356
6363
 
6357
- def changes(self) -> int:
6364
+ async def changes(self) -> int:
6358
6365
  """Returns the number of database rows that were changed (or inserted
6359
6366
  or deleted) by the most recently completed INSERT, UPDATE, or DELETE
6360
6367
  statement.
@@ -6677,7 +6684,9 @@ class AsyncConnection:
6677
6684
  """If *keep* is *None* then all registered virtual tables are dropped.
6678
6685
 
6679
6686
  Otherwise *keep* is a sequence of strings, naming the virtual tables that
6680
- are kept, dropping all others."""
6687
+ are kept, dropping all others.
6688
+
6689
+ Calls: `sqlite3_drop_modules <https://sqlite.org/c3ref/drop_modules.html>`__"""
6681
6690
  ...
6682
6691
 
6683
6692
  async def enable_load_extension(self, enable: bool) -> None:
@@ -6819,8 +6828,10 @@ class AsyncConnection:
6819
6828
  * `FTS5 documentation <https://www.sqlite.org/fts5.html#custom_tokenizers>`__"""
6820
6829
  ...
6821
6830
 
6822
- def get_autocommit(self) -> bool:
6823
- """Returns if the Connection is in auto commit mode (ie not in a transaction).
6831
+ async def get_autocommit(self) -> bool:
6832
+ """Returns if the Connection is in auto commit mode (ie not in a
6833
+ transaction). It is recommended to use :meth:`txn_state` instead
6834
+ which is more reliable.
6824
6835
 
6825
6836
  Calls: `sqlite3_get_autocommit <https://sqlite.org/c3ref/get_autocommit.html>`__"""
6826
6837
  ...
@@ -6835,7 +6846,7 @@ class AsyncConnection:
6835
6846
  <Connection.row_trace>`"""
6836
6847
  ...
6837
6848
 
6838
- in_transaction: bool
6849
+ in_transaction: Awaitable[bool]
6839
6850
  """It is recommended to use :meth:`txn_state` instead which is more reliable.
6840
6851
 
6841
6852
  Calls: `sqlite3_get_autocommit <https://sqlite.org/c3ref/get_autocommit.html>`__"""
@@ -6859,8 +6870,11 @@ class AsyncConnection:
6859
6870
 
6860
6871
  Calls: `sqlite3_is_interrupted <https://sqlite.org/c3ref/interrupt.html>`__"""
6861
6872
 
6862
- def last_insert_rowid(self) -> int:
6873
+ async def last_insert_rowid(self) -> int:
6863
6874
  """Returns the integer key of the most recent insert in the database.
6875
+ It is recommended to use SQL `RETURNING <https://sqlite.org/lang_returning.html>`__
6876
+ instead because that ensures you get the rowid directly from the
6877
+ SQL that made the change.
6864
6878
 
6865
6879
  Calls: `sqlite3_last_insert_rowid <https://sqlite.org/c3ref/last_insert_rowid.html>`__"""
6866
6880
  ...
@@ -7288,7 +7302,7 @@ class AsyncConnection:
7288
7302
  Calls: `sqlite3_table_column_metadata <https://sqlite.org/c3ref/table_column_metadata.html>`__"""
7289
7303
  ...
7290
7304
 
7291
- def total_changes(self) -> int:
7305
+ async def total_changes(self) -> int:
7292
7306
  """Returns the total number of database rows that have be modified,
7293
7307
  inserted, or deleted since the database connection was opened.
7294
7308
 
@@ -27,10 +27,6 @@
27
27
  "description": "A VFS shim that writes a checksum on each page of an SQLite database file",
28
28
  "type": "extension"
29
29
  },
30
- "closure": {
31
- "description": "A virtual table that finds the transitive closure of a parent/child relationship in a real table",
32
- "type": "extension"
33
- },
34
30
  "completion": {
35
31
  "description": "A virtual table that returns suggested completions for a partial SQL input",
36
32
  "type": "extension"
@@ -183,7 +183,7 @@ class BadIsTrue(int):
183
183
  class ThreadRunner(threading.Thread):
184
184
  def __init__(self, callable, *args, **kwargs):
185
185
  threading.Thread.__init__(self)
186
- self.daemon - True
186
+ self.daemon = True
187
187
  self.callable = callable
188
188
  self.args = args
189
189
  self.kwargs = kwargs
@@ -234,7 +234,11 @@ def bgdel():
234
234
  bgdelq = queue.Queue()
235
235
  bgdelthread = threading.Thread(target=bgdel)
236
236
  bgdelthread.daemon = True
237
- bgdelthread.start()
237
+ try:
238
+ bgdelthread.start()
239
+ except RuntimeError:
240
+ # wasm build can't do this
241
+ pass
238
242
 
239
243
 
240
244
  def deletefile(name):
@@ -397,7 +401,11 @@ class APSW(unittest.TestCase):
397
401
  val = exc
398
402
 
399
403
  t = threading.Thread(target=thread, daemon=True)
400
- t.start()
404
+ try:
405
+ t.start()
406
+ except RuntimeError:
407
+ # wasm can't start thread
408
+ return
401
409
  t.join(1)
402
410
  if val != 3:
403
411
  raise val
@@ -3187,7 +3195,7 @@ class APSW(unittest.TestCase):
3187
3195
 
3188
3196
  # for coverage
3189
3197
  self.db.cache_flush()
3190
- getattr(self.db, "release_memory")() # avoids old name testing false positive
3198
+ getattr(self.db, "release" + "_" + "memory")() # avoids old name testing false positive
3191
3199
 
3192
3200
  c.execute("commit")
3193
3201
  self.assertEqual(300, self.db.total_changes())
@@ -3702,7 +3710,10 @@ class APSW(unittest.TestCase):
3702
3710
  vals["stop"] = True
3703
3711
 
3704
3712
  t = ThreadRunner(wt)
3705
- t.start()
3713
+ try:
3714
+ t.start()
3715
+ except RuntimeError:
3716
+ return
3706
3717
  # ensure thread t has started
3707
3718
  time.sleep(0.1)
3708
3719
  b4 = time.time()
@@ -5065,7 +5076,10 @@ class APSW(unittest.TestCase):
5065
5076
  db2 = apsw.Connection(self.db.filename)
5066
5077
  db2.set_busy_timeout(30000)
5067
5078
  t = ThreadRunner(db2.cursor().execute, "select * from foo")
5068
- t.start()
5079
+ try:
5080
+ t.start()
5081
+ except RuntimeError:
5082
+ return
5069
5083
  time.sleep(1)
5070
5084
  self.db.cursor().execute("commit")
5071
5085
  t.go()
@@ -5181,7 +5195,10 @@ class APSW(unittest.TestCase):
5181
5195
  end = time.time() + runtime
5182
5196
  threads = [threading.Thread(target=dostuff, args=(end,)) for _ in range(20)]
5183
5197
  for t in threads:
5184
- t.start()
5198
+ try:
5199
+ t.start()
5200
+ except RuntimeError:
5201
+ return
5185
5202
 
5186
5203
  for t in threads:
5187
5204
  t.join()
@@ -6022,20 +6039,25 @@ class APSW(unittest.TestCase):
6022
6039
  f"file {filename} function {name} calls PyGILState_Ensure but does not have MakeExistingException"
6023
6040
  )
6024
6041
  # not further checked
6025
- if name.split("_")[0] in (
6026
- "ZeroBlobBind",
6027
- "APSWVFS",
6028
- "APSWVFSFile",
6029
- "APSWBuffer",
6030
- "FunctionCBInfo",
6031
- "APSWFTS5Tokenizer",
6032
- "cursor",
6033
- "APSWChangesetIterator",
6034
- "JSONB",
6035
- "AwaitableWrapper",
6036
- "BoxedCall",
6037
- "APSWChangeset",
6038
- ) or name in {"apsw_no_change_repr", "convert_column_to_pyobject"}:
6042
+ if (
6043
+ name.split("_")[0]
6044
+ in (
6045
+ "ZeroBlobBind",
6046
+ "APSWVFS",
6047
+ "APSWVFSFile",
6048
+ "APSWBuffer",
6049
+ "FunctionCBInfo",
6050
+ "APSWFTS5Tokenizer",
6051
+ "cursor",
6052
+ "APSWChangesetIterator",
6053
+ "JSONB",
6054
+ "AwaitableWrapper",
6055
+ "BoxedCall",
6056
+ "APSWChangeset",
6057
+ )
6058
+ or name in {"apsw_no_change_repr", "convert_column_to_pyobject"}
6059
+ or name.split("_")[:2] == ["apsw", "module"]
6060
+ ):
6039
6061
  return
6040
6062
 
6041
6063
  checks = {
@@ -7313,6 +7335,12 @@ class APSW(unittest.TestCase):
7313
7335
  "Verify VFS functionality"
7314
7336
  global testtimeout
7315
7337
 
7338
+ if sys.platform == "emscripten":
7339
+ # there is some weird issued inside this environment +
7340
+ # sqlite where writes aren't getting flushed before a read
7341
+ # which means the obfuscated database doesn't work.
7342
+ return
7343
+
7316
7344
  testdb = vfstestdb
7317
7345
 
7318
7346
  # some coverage related stuff
@@ -8831,7 +8859,10 @@ class APSW(unittest.TestCase):
8831
8859
 
8832
8860
  runtime = float(os.getenv("APSW_HEAVY_DURATION")) if os.getenv("APSW_HEAVY_DURATION") else 30
8833
8861
  t = ThreadRunner(wt)
8834
- t.start()
8862
+ try:
8863
+ t.start()
8864
+ except RuntimeError:
8865
+ return
8835
8866
  b4 = time.time()
8836
8867
  # try to get concurrency error
8837
8868
  try:
@@ -69,7 +69,10 @@ class Async(unittest.TestCase):
69
69
  res.append(apsw.async_run_coro)
70
70
 
71
71
  t = threading.Thread(target=check)
72
- t.start()
72
+ try:
73
+ t.start()
74
+ except RuntimeError:
75
+ return
73
76
  t.join()
74
77
 
75
78
  self.assertEqual(res, [None])
@@ -1331,7 +1334,12 @@ class Async(unittest.TestCase):
1331
1334
 
1332
1335
  for fn in self.get_all_atests():
1333
1336
  with self.subTest(fw="asyncio", fn=fn):
1334
- asyncio.run(self.asyncTearDown(fn("asyncio")), debug=False)
1337
+ try:
1338
+ asyncio.run(self.asyncTearDown(fn("asyncio")), debug=False)
1339
+ except RuntimeError as exc:
1340
+ if "can't start new thread" in str(exc):
1341
+ return
1342
+ raise
1335
1343
 
1336
1344
  def testTrio(self):
1337
1345
  import importlib.metadata
@@ -1408,7 +1416,7 @@ class Async(unittest.TestCase):
1408
1416
  def testNoIO(self):
1409
1417
  "no async running"
1410
1418
  self.assertRaisesRegex(
1411
- RuntimeError, "Unable to determine current Async environment", apsw.Connection.as_async, ""
1419
+ RuntimeError, "(Unable to determine current Async environment|can't start new thread)", apsw.Connection.as_async, ""
1412
1420
  )
1413
1421
 
1414
1422
 
@@ -55,6 +55,9 @@ class Extra(unittest.TestCase):
55
55
  self.assertGreater(num_diff, 0)
56
56
 
57
57
  def testExecutable(self):
58
+ if sys.platform == "emscripten":
59
+ return
60
+
58
61
  spicy = "√π⁷≤∞"
59
62
 
60
63
  with tempfile.TemporaryDirectory(prefix=f"apsw-extra-{spicy}-test") as tmpd:
@@ -512,6 +512,10 @@ class FTS(unittest.TestCase):
512
512
 
513
513
  def testCLI(self):
514
514
  "Test command line interface"
515
+
516
+ if sys.platform == "emscripten":
517
+ return
518
+
515
519
  if coverage_run:
516
520
  cov_params = ["-m", "coverage", "run", "--source", "apsw", "-p"]
517
521
  env = os.environ.copy()
@@ -2243,6 +2247,10 @@ class Unicode(unittest.TestCase):
2243
2247
 
2244
2248
  def testCLI(self):
2245
2249
  "Exercise command line interface"
2250
+
2251
+ if sys.platform == "emscripten":
2252
+ return
2253
+
2246
2254
  text = ""
2247
2255
  for codepoints in self.cat_examples.values():
2248
2256
  # surrogates not allowed
@@ -122,7 +122,12 @@ class MultipleCiphers(unittest.TestCase):
122
122
  time.sleep(0.5)
123
123
  self.db.execute("end")
124
124
 
125
- threading.Thread(target=busy).start()
125
+ t = threading.Thread(target=busy)
126
+ try:
127
+ t.start()
128
+ except RuntimeError:
129
+ # wasm can't start thread
130
+ return
126
131
 
127
132
  self.assertRaises(apsw.BusyError, apply_encryption, con2, key="hello world")
128
133
  con2.set_busy_timeout(1000)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apsw-sqlite3mc
3
- Version: 3.53.2.0
3
+ Version: 3.53.3.1
4
4
  Summary: SQLite3 Multiple Ciphers combined with Another Python SQLite Wrapper
5
5
  Home-page: https://github.com/utelle/apsw-sqlite3mc
6
6
  Author: Ulrich Telle
@@ -90,7 +90,7 @@ Setting the key on a new database is the only change needed to your code.
90
90
 
91
91
  >>> import apsw
92
92
  >>> print(apsw.mc_version)
93
- SQLite3 Multiple Ciphers 2.3.5
93
+ SQLite3 Multiple Ciphers 2.3.6
94
94
  >>> con = apsw.Connection("database.sqlite3")
95
95
  >>> con.pragma("key", "my secret passphrase")
96
96
  ok
@@ -18,9 +18,11 @@ https://sqlite.org/vec1/zip/vec1-20260306155250-d070184523.zip 75980 6a58eebbe1e
18
18
  https://sqlite.org/sqlar/zip/sqlar-src-20180107193712-4824e73896.zip 1980460 63bc4b3459fd00498f161d87d8b4516a581278da900001af183486458396806c c7b6a21b58e7499b7c3e36f26b7fafe44ddbd85097b37d905d72ccf5ff3e7cb8
19
19
 
20
20
 
21
- https://www.zlib.net/zlib132.zip 1616754 e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 6b35b981f73425dc5f142cbee457f078d42240c022c804982849b962f1d1e2c6
21
+ https://github.com/madler/zlib/releases/download/v1.3.2/zlib132.zip 1616754 e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 6b35b981f73425dc5f142cbee457f078d42240c022c804982849b962f1d1e2c6
22
22
 
23
23
  # SQLite releases
24
+ https://sqlite.org/2026/sqlite-autoconf-3530300.tar.gz 3282443 c917d7db16648ec95f714974ace5e5dcf46b7dc70e26600a0a102a3141125db0 98f2b3f3c11be6a03ea32346937b032c2472ebbd7a716bed36ca2f5693e7ce8b
25
+ https://sqlite.org/2026/sqlite-src-3530300.zip 14537772 bb80bf8a3bffc19241ce8aba5a4bc74e9c3980013cb0b5f0f0976a99516942af 2daecfa16e3b19e058dc2e2cb717b80ade361e0315aa5376c3619f66aa81e181
24
26
  https://sqlite.org/2026/sqlite-autoconf-3530200.tar.gz 3279926 588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316 025328da165109f48abccc6e7478508060804412bed2bd81d47e98ba1b72983b
25
27
  https://sqlite.org/2026/sqlite-src-3530200.zip 14527073 cafff764c03f6d720968f746e2f47a986bbf12bf4c18904f1eb131c0b0b592d3 490ec7af32a6bfa5f3e05dc279c04286cfe3f328def4a8b7344e3fa20be18a4c
26
28
  https://sqlite.org/2026/sqlite-autoconf-3530100.tar.gz 3275272 83e6b2020a034e9a7ad4a72feea59e1ad52f162e09cbd26735a3ffb98359fc4f 36ca143645cf76997d07b66e9244c636b8ccdec64a1d50558259c4e415e6558b
@@ -316,7 +316,7 @@ class fetch(Command):
316
316
  ),
317
317
  (
318
318
  "zlib source",
319
- "https://www.zlib.net/zlib132.zip",
319
+ "https://github.com/madler/zlib/releases/download/v1.3.2/zlib132.zip",
320
320
  "sqlite3/zlib",
321
321
  ),
322
322
  ):
@@ -359,7 +359,9 @@ class fetch(Command):
359
359
  val = sysconfig.get_config_var(v)
360
360
  if val:
361
361
  env[v] = val
362
- subprocess.check_call(["./configure"], cwd="sqlite3", env=env)
362
+ # configure failing to run is ignored - this happens with
363
+ # linux host doing emscripten etc
364
+ subprocess.call(["./configure"], cwd="sqlite3", env=env)
363
365
 
364
366
 
365
367
  # We allow enable/omit to be specified to build and then pass them to build_ext
@@ -893,12 +895,14 @@ def download(url: str, checksum: bool = True, missing_checksum_ok: bool = False)
893
895
  cache_name = cache_dir / file_name
894
896
  if cache_name.exists():
895
897
  try:
896
- if abs(time.time() - cache_name.stat().st_mtime) < 7 *24 * 60 * 60:
898
+ if abs(time.time() - cache_name.stat().st_mtime) < 7 * 24 * 60 * 60:
897
899
  page = (cache_dir / file_name).read_bytes()
898
900
  write(" Cached", url)
899
901
  if checksum:
900
902
  verifyurl(url, page, missing_checksum_ok)
901
903
  return io.BytesIO(page)
904
+ # remove stale file
905
+ cache_name.unlink()
902
906
  except Exception:
903
907
  # many things could go wrong in the above including being
904
908
  # unable to stat, unable to read etc, so we fallback to a