Coverage for tests/test_optional_dependencies.py: 100%

29 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-01 20:15 +0300

1"""Optional backend dependency contract tests.""" 

2 

3from __future__ import annotations 

4 

5import subprocess 

6import sys 

7from importlib.metadata import metadata 

8 

9from snektest import assert_eq, assert_in, test 

10 

11 

12def _run_python(script: str) -> subprocess.CompletedProcess[str]: 

13 """Run an import-isolated Python snippet in the current test environment.""" 

14 

15 return subprocess.run( 

16 [sys.executable, "-c", script], 

17 check=False, 

18 capture_output=True, 

19 text=True, 

20 ) 

21 

22 

23@test() 

24def package_metadata_declares_backend_driver_extras() -> None: 

25 """SQLite and MariaDB drivers are optional backend extras.""" 

26 

27 package_metadata = metadata("snekql") 

28 extras = package_metadata.get_all("Provides-Extra") or [] 

29 requirements = package_metadata.get_all("Requires-Dist") or [] 

30 

31 assert_in("aiosqlite", extras) 

32 assert_in("aiomysql", extras) 

33 assert any( 

34 requirement.startswith("aiosqlite") and "extra == 'aiosqlite'" in requirement 

35 for requirement in requirements 

36 ) 

37 assert any( 

38 requirement.startswith("aiomysql") and "extra == 'aiomysql'" in requirement 

39 for requirement in requirements 

40 ) 

41 assert not any( 

42 requirement.startswith(("aiosqlite", "aiomysql")) 

43 and "extra ==" not in requirement 

44 for requirement in requirements 

45 ) 

46 

47 

48@test() 

49def public_imports_do_not_import_optional_drivers() -> None: 

50 """Root and backend namespace imports do not load optional database drivers.""" 

51 

52 script = """ 

53import sys 

54import snekql 

55from tests.logging_helpers import NULL_LOGGER 

56from snekql import mariadb, sqlite 

57 

58if "aiosqlite" in sys.modules: 

59 raise AssertionError("aiosqlite was imported") 

60if "aiomysql" in sys.modules: 

61 raise AssertionError("aiomysql was imported") 

62if "snekql._pool" in sys.modules: 

63 raise AssertionError("SQLite pool was imported") 

64if "snekql.schema" in sys.modules: 

65 raise AssertionError("SQLite schema was imported") 

66_ = sqlite.Config(database=":memory:") 

67_ = mariadb.Config(database="app", user="snekql") 

68print("ok") 

69""" 

70 

71 result = _run_python(script) 

72 

73 assert_eq(result.returncode, 0) 

74 assert_eq(result.stdout.strip(), "ok") 

75 

76 

77@test(mark="medium") 

78def sqlite_initialization_without_extra_reports_install_hint() -> None: 

79 """Runtime initialization explains how to install a missing SQLite driver.""" 

80 

81 script = """ 

82from __future__ import annotations 

83 

84import asyncio 

85import builtins 

86 

87import snekql 

88from snekql import Database, sqlite 

89from tests.logging_helpers import NULL_LOGGER 

90 

91original_import = builtins.__import__ 

92 

93 

94def block_aiosqlite(name, globals=None, locals=None, fromlist=(), level=0): 

95 if name == "aiosqlite" or name.startswith("aiosqlite."): 

96 raise ModuleNotFoundError("No module named 'aiosqlite'", name="aiosqlite") 

97 return original_import(name, globals, locals, fromlist, level) 

98 

99 

100async def main() -> None: 

101 builtins.__import__ = block_aiosqlite 

102 try: 

103 try: 

104 _ = await Database.initialize(NULL_LOGGER, sqlite.Config(database=":memory:")) 

105 except snekql.DatabaseRuntimeError as error: 

106 print(error) 

107 return 

108 raise AssertionError("SQLite initialization unexpectedly succeeded") 

109 finally: 

110 builtins.__import__ = original_import 

111 

112 

113asyncio.run(main()) 

114""" 

115 

116 result = _run_python(script) 

117 

118 assert_eq(result.returncode, 0) 

119 assert_in("snekql[aiosqlite]", result.stdout)