mirror of
https://github.com/python/cpython
synced 2026-11-06 09:02:40 +03:00
54 lines
1.6 KiB
Python
54 lines
1.6 KiB
Python
import unittest
|
|
|
|
from test import support
|
|
from test.support import import_helper, threading_helper
|
|
from test.support.threading_helper import run_concurrently
|
|
|
|
|
|
sqlite3 = import_helper.import_module("sqlite3")
|
|
|
|
|
|
NAME = "FREE_THREADING_RACE"
|
|
NCOLUMNS = 64
|
|
NITER = 3000
|
|
QUERY = "select " + ", ".join(
|
|
f"'value' as 'c{i} [{NAME}]'" for i in range(NCOLUMNS)
|
|
)
|
|
|
|
|
|
@threading_helper.requires_working_threading()
|
|
class TestSQLite3(unittest.TestCase):
|
|
def test_concurrent_converter_replacement(self):
|
|
# gh-155781: Converter lookups must retain a strong reference while
|
|
# another thread updates the public converter registry.
|
|
class Converter:
|
|
__slots__ = ("value",)
|
|
|
|
def __init__(self, value):
|
|
self.value = value
|
|
|
|
def __call__(self, value):
|
|
return self.value
|
|
|
|
def reader():
|
|
con = sqlite3.connect(":memory:",
|
|
detect_types=sqlite3.PARSE_COLNAMES)
|
|
try:
|
|
for _ in range(NITER):
|
|
row = con.execute(QUERY).fetchone()
|
|
self.assertEqual(len(row), NCOLUMNS)
|
|
finally:
|
|
con.close()
|
|
|
|
def mutator():
|
|
for i in range(NITER * NCOLUMNS):
|
|
sqlite3.register_converter(NAME, Converter(i))
|
|
if i % 3 == 0:
|
|
sqlite3.converters.pop(NAME, None)
|
|
|
|
with support.swap_item(sqlite3.converters, NAME, Converter(0)):
|
|
run_concurrently([reader] * 8 + [mutator] * 2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|