sqlalchemy-dqlite 0.3.0__tar.gz → 0.4.0__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 (280) hide show
  1. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/PKG-INFO +5 -5
  2. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/docs/transactions.md +18 -0
  3. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/pyproject.toml +4 -4
  4. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/__init__.py +1 -1
  5. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/base.py +21 -60
  6. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/requirements.py +1 -2
  7. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/conftest.py +0 -14
  8. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_stale_rows.py +2 -2
  9. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_suppress_and_soft_close_noop.py +2 -2
  10. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_creator_fn_noncallable_rejected.py +1 -3
  11. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_closed_guards.py +1 -1
  12. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_executemany_leader_flip_state_reset.py +1 -1
  13. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_detect_autocommit_setting.py +6 -9
  14. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_dialect_config.py +10 -4
  15. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/uv.lock +4 -4
  16. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/.github/workflows/publish-to-pypi.yml +0 -0
  17. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/.gitignore +0 -0
  18. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/DEVELOPMENT.md +0 -0
  19. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/LICENSE.md +0 -0
  20. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/README.md +0 -0
  21. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/docs/connection-url.md +0 -0
  22. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/docs/limitations.md +0 -0
  23. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/scripts/check-commit-msg.sh +0 -0
  24. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/setup.cfg +0 -0
  25. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/aio.py +0 -0
  26. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/provision.py +0 -0
  27. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/src/sqlalchemydqlite/py.typed +0 -0
  28. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/__init__.py +0 -0
  29. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/compliance/conftest.py +0 -0
  30. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/compliance/test_suite.py +0 -0
  31. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/__init__.py +0 -0
  32. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/conftest.py +0 -0
  33. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_cancel_during_commit_invalidates_slot.py +0 -0
  34. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_cancel_inside_engine_begin.py +0 -0
  35. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_concurrent_sessions.py +0 -0
  36. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_context.py +0 -0
  37. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_executemany.py +0 -0
  38. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_async_savepoint_cancellation_invalidates_slot.py +0 -0
  39. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_bulk_dml_returning.py +0 -0
  40. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_concurrent_writers_begin_immediate.py +0 -0
  41. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_date_tz_drop.py +0 -0
  42. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_dial_func_via_connect_args_reaches_dbapi.py +0 -0
  43. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_dqlite_session_mode_execution_option.py +0 -0
  44. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_engine_begin_is_atomic.py +0 -0
  45. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_engine_events_fire.py +0 -0
  46. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_inspect_async_and_close_parity.py +0 -0
  47. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_isolation_level_pin.py +0 -0
  48. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_json_column.py +0 -0
  49. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_native_boolean.py +0 -0
  50. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_orm_operations.py +0 -0
  51. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_pool_pre_ping_leader_flip.py +0 -0
  52. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_pool_recycle_and_dispose_fan_out.py +0 -0
  53. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_pool_reset_on_return.py +0 -0
  54. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_reflect_column_types.py +0 -0
  55. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_savepoint_basic.py +0 -0
  56. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_savepoint_orm_session_begin_nested.py +0 -0
  57. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_savepoint_quoted_identifiers.py +0 -0
  58. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_temp_table_scoping_per_connection.py +0 -0
  59. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_time_and_reflection.py +0 -0
  60. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/integration/test_upsert.py +0 -0
  61. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_2pc_not_supported_error.py +0 -0
  62. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_arraysize_default_and_semantics.py +0 -0
  63. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_arraysize_validation.py +0 -0
  64. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_cursor_iterator_protocol.py +0 -0
  65. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_fetchmany_negative.py +0 -0
  66. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_handle_exception_hook.py +0 -0
  67. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_pickle_guards.py +0 -0
  68. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_adapter_slots.py +0 -0
  69. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_adapted_connection_public_paths.py +0 -0
  70. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_async_creator_fn.py +0 -0
  71. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_async_creator_fn_shape_check.py +0 -0
  72. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_async_ping_closed_proxy_log.py +0 -0
  73. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_await_staticmethod.py +0 -0
  74. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_final_close_suppression.py +0 -0
  75. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_loop_mismatch_remap.py +0 -0
  76. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_releases_inner_connection_pin.py +0 -0
  77. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_rollback_log.py +0 -0
  78. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_rollback_loop_already_running_remap.py +0 -0
  79. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_rollback_runtime_error_case_insensitive.py +0 -0
  80. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_terminate_cancellederror_force_close.py +0 -0
  81. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_terminate_in_greenlet_preflight.py +0 -0
  82. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_terminate_outside_greenlet.py +0 -0
  83. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_terminate_proxy_swap_arms.py +0 -0
  84. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_close_terminate_runtime_error_post_await.py +0 -0
  85. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_connect_construction_in_try_frame.py +0 -0
  86. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_connect_loop_state_remap.py +0 -0
  87. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_cursor_class_hooks.py +0 -0
  88. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_cursor_closed_before_server_side_precedence.py +0 -0
  89. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_cursor_time_error_remapped.py +0 -0
  90. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_dialect_do_close_releases_inner_strong_ref.py +0 -0
  91. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_do_close_fallback_force_close_transport.py +0 -0
  92. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_do_ping_cursor_construct_exception_arms.py +0 -0
  93. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_do_ping_override.py +0 -0
  94. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_do_ping_runtimeerror_returns_false.py +0 -0
  95. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_do_terminate_suppresses_exception.py +0 -0
  96. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_force_close_transport_cancelled_error.py +0 -0
  97. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_force_close_transport_dead_proxy.py +0 -0
  98. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_force_close_transport_docstring_pins.py +0 -0
  99. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_handle_exception_baseexceptiongroup_cancel_split.py +0 -0
  100. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_handle_exception_call_sites.py +0 -0
  101. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_handle_exception_delegates_to_remap_helper.py +0 -0
  102. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_handle_exception_group_single_child_unwrap.py +0 -0
  103. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_is_disconnect_closed_proxy.py +0 -0
  104. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_post_close_proxy_guards.py +0 -0
  105. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_terminate.py +0 -0
  106. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_aio_terminate_close_idempotence.py +0 -0
  107. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_cursor_closed_check.py +0 -0
  108. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_execute_handle_exception.py +0 -0
  109. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_execute_suppress_cancellederror.py +0 -0
  110. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_init_positional_swap_guard.py +0 -0
  111. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_init_sa_reference_signature.py +0 -0
  112. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_connection_init_three_call_shapes.py +0 -0
  113. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapted_cursor_sync_ctxmgr.py +0 -0
  114. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter.py +0 -0
  115. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_autocommit_property.py +0 -0
  116. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_closed_checks.py +0 -0
  117. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_lastrowid_sticky.py +0 -0
  118. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_op_lock_serialisation.py +0 -0
  119. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_terminate_handled_exceptions.py +0 -0
  120. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_adapter_terminate_handled_exceptions_runtimeerror.py +0 -0
  121. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_commit_cancel_invalidates_slot.py +0 -0
  122. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_after_connection_close.py +0 -0
  123. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_arraysize_accepts_zero_and_negative.py +0 -0
  124. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_arraysize_propagates_to_underlying.py +0 -0
  125. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_closed_guard.py +0 -0
  126. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_execute_close_suppress_behavioural.py +0 -0
  127. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_executemany_listifies_iterable.py +0 -0
  128. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_handle_exception.py +0 -0
  129. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_cursor_sync_only_context_manager.py +0 -0
  130. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_dialect_isolation_set.py +0 -0
  131. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_handle_exception_case_insensitive.py +0 -0
  132. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_handle_exception_cause_walk.py +0 -0
  133. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_isolation_level.py +0 -0
  134. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_ping_cancel_cleanup.py +0 -0
  135. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_ping_close_arm_narrow_vs_programmer_bug.py +0 -0
  136. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_ping_single_execute_no_fetchone.py +0 -0
  137. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_async_ping_translates_dead_proxy_to_interface_error.py +0 -0
  138. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_audit_2026_05_round2_sa_changes.py +0 -0
  139. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_audit_2026_05_sa_changes.py +0 -0
  140. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_audit_2026_05_sa_coverage.py +0 -0
  141. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_bind_side_cross_type_rejection.py +0 -0
  142. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_busy_timeout_url_and_connect_args.py +0 -0
  143. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_check_same_thread_url_and_connect_args.py +0 -0
  144. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_close_runs_close_after_rollback_raise.py +0 -0
  145. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_collated_coverage_gaps.py +0 -0
  146. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_colspecs_pysqlite_time_inherited_baseline.py +0 -0
  147. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_compiler_regexp_match.py +0 -0
  148. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_compliance_conftest_staleness_pin.py +0 -0
  149. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_connect_args_kwarg_validation.py +0 -0
  150. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_connect_args_value_validators.py +0 -0
  151. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_cross_package_version_parity.py +0 -0
  152. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_cursor_close_narrow_suppress.py +0 -0
  153. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_datetime_bind_widens_date.py +0 -0
  154. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_datetime_date_parse_errors.py +0 -0
  155. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_datetime_time_cross_type_payload.py +0 -0
  156. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_datetime_tz_conversion.py +0 -0
  157. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_ddl_kwarg_dqlite_prefix_rejected.py +0 -0
  158. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_ddl_kwarg_prefix_documented.py +0 -0
  159. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_description_alias_shared.py +0 -0
  160. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dial_attempt_timeout_url_and_connect_args.py +0 -0
  161. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect.py +0 -0
  162. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_docstring_pins.py +0 -0
  163. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_final_annotated.py +0 -0
  164. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_inherits_pysqlite.py +0 -0
  165. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_init_eager_autocommit_rejection.py +0 -0
  166. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_init_preserves_pins.py +0 -0
  167. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_ipv6_url.py +0 -0
  168. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_sqlite_incompatibility_flags_pinned.py +0 -0
  169. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dialect_url_credentials.py +0 -0
  170. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_disconnect_substring_producer_emission.py +0 -0
  171. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_begin_cancel.py +0 -0
  172. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_begin_cursor_close_widened_catch.py +0 -0
  173. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_begin_emits_begin.py +0 -0
  174. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_close_calls_dbapi_close_directly.py +0 -0
  175. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_close_fallback_suppress_arm.py +0 -0
  176. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_close_fallback_uses_sync_transport_teardown.py +0 -0
  177. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_close_first_arm_absorbs_runtime_error.py +0 -0
  178. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_execute_local_override_pin.py +0 -0
  179. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_executemany_local_override_pin.py +0 -0
  180. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_catches_programming_error.py +0 -0
  181. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_close_narrow.py +0 -0
  182. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_cursor_call_disconnect.py +0 -0
  183. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_database_error.py +0 -0
  184. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_dialect_specific_select_one.py +0 -0
  185. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_interface_error_with_code.py +0 -0
  186. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_ping_non_disconnect_databaseerror_reraise.py +0 -0
  187. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_recover_twophase_noreturn_annotation.py +0 -0
  188. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_terminate_narrow_catch_propagates_refactor_break.py +0 -0
  189. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_do_terminate_non_raising_contract_widened.py +0 -0
  190. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlite_datetime_bind_zero_microseconds.py +0 -0
  191. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlite_datetime_time_literal_processor_microseconds.py +0 -0
  192. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlite_datetime_types_reject_pysqlite_kwargs.py +0 -0
  193. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlite_time_bind_processor_combined_fixes.py +0 -0
  194. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlite_time_result_processor_preserves_offset.py +0 -0
  195. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlitetime_bind_processor_returns_none.py +0 -0
  196. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_dqlitetime_cross_axis_narrow_with_timezone_true.py +0 -0
  197. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_drift_defence_pins.py +0 -0
  198. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_drop_user_tables_log_record_bounded.py +0 -0
  199. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_floor_compile_time_gate.py +0 -0
  200. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_handle_exception_must_raise.py +0 -0
  201. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_handle_exception_remap.py +0 -0
  202. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_handle_exception_two_pass_recovery_after_mixed_cancel_group.py +0 -0
  203. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_bare_databaseerror_type_identity.py +0 -0
  204. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_bare_dbe_short_circuits_on_slot_fatal_codes.py +0 -0
  205. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_bare_oserror_walked_not_early_return.py +0 -0
  206. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_case_insensitive.py +0 -0
  207. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_cause_walk.py +0 -0
  208. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_closed_handle_with_id_suffix.py +0 -0
  209. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_cluster_error.py +0 -0
  210. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_database_error_substring.py +0 -0
  211. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_event_loop_already_running_prefix.py +0 -0
  212. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_event_loop_closed.py +0 -0
  213. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_event_loop_mismatch_substring.py +0 -0
  214. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_exception_group_and_substring_walk.py +0 -0
  215. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_interface_error_cause_walk.py +0 -0
  216. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_leader_lost_substring_case_insensitive.py +0 -0
  217. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_notfound_lookup_db.py +0 -0
  218. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_oe_code_restriction.py +0 -0
  219. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_protocol_error_arm.py +0 -0
  220. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_raft_collapse.py +0 -0
  221. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_raw_message.py +0 -0
  222. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_recognises_connection_invalidated_interfaceerror.py +0 -0
  223. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_recognises_cross_loop_interfaceerror.py +0 -0
  224. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_recognises_used_after_fork.py +0 -0
  225. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_substring_visible_within_dbapi_4kib_cap.py +0 -0
  226. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_untracked_savepoint_negative.py +0 -0
  227. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_is_disconnect_walks_cause_oserror.py +0 -0
  228. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_isolation_level_in_connect_args_directional_message.py +0 -0
  229. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_isolation_lookup_vs_values_list_divergence_documented.py +0 -0
  230. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_leader_error_codes_identity.py +0 -0
  231. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_log_safe_peer_helper.py +0 -0
  232. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_log_safe_peer_uses_sanitize_for_log.py +0 -0
  233. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_max_message_size_url_and_connect_args.py +0 -0
  234. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_max_total_rows_warning_does_not_advertise_disabled_token.py +0 -0
  235. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_phantom_returning_flag_does_not_exist_in_sa.py +0 -0
  236. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_create_drop_db_log_sanitises_ident.py +0 -0
  237. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_drop_user_tables_and_reap.py +0 -0
  238. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_drop_user_tables_log_sanitized.py +0 -0
  239. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_drop_user_tables_quote_escaping.py +0 -0
  240. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_format_url_ident_sanitisation.py +0 -0
  241. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_generate_driver_url.py +0 -0
  242. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_reap_dbs_info_log_credential_mask_and_sanitize.py +0 -0
  243. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_reap_dbs_log_sanitized.py +0 -0
  244. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_session_token_shape.py +0 -0
  245. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_provision_upsert.py +0 -0
  246. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_public_api.py +0 -0
  247. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_raft_collapse_markers_upstream_provenance.py +0 -0
  248. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_remap_loop_state_chains_from_matched_hop.py +0 -0
  249. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_requirements.py +0 -0
  250. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_requirements_closed_marker_present.py +0 -0
  251. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_requirements_recently_opened.py +0 -0
  252. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_reset_isolation_level_is_local_noop.py +0 -0
  253. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_result_processor_debug_arm_isenabledfor_guard.py +0 -0
  254. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_result_processor_edge_branches.py +0 -0
  255. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_result_processor_log_payload_sanitized.py +0 -0
  256. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_result_processor_log_truncates_server_text.py +0 -0
  257. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_result_processor_warning_one_shot.py +0 -0
  258. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_savepoint_leader_flip_loud_failure.py +0 -0
  259. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_set_isolation_level_case_insensitive.py +0 -0
  260. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_set_isolation_level_none_rejected.py +0 -0
  261. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_stream_results_documented_eager_buffer.py +0 -0
  262. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_submodule_all.py +0 -0
  263. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_sync_connect_creator_fn_shape.py +0 -0
  264. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_sync_do_rollback_transport_fault_classified.py +0 -0
  265. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_sync_do_terminate.py +0 -0
  266. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_sync_do_terminate_log_includes_peer_and_id.py +0 -0
  267. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_time_colspec.py +0 -0
  268. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_time_tz_conversion.py +0 -0
  269. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_top_level_logger_has_null_handler.py +0 -0
  270. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_transitive_wire_import.py +0 -0
  271. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_transport_class_exceptions_consolidation.py +0 -0
  272. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_url_int_upper_boundary_off_by_one.py +0 -0
  273. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_url_max_rows_none_token.py +0 -0
  274. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_url_pre_validation.py +0 -0
  275. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_url_timeout_validators_share_ssot.py +0 -0
  276. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_version.py +0 -0
  277. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_walk_cause_chain_caps_pathological_group_size.py +0 -0
  278. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_walk_cause_chain_cycle_at_depth.py +0 -0
  279. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_walk_cause_chain_depth_budget.py +0 -0
  280. {sqlalchemy_dqlite-0.3.0 → sqlalchemy_dqlite-0.4.0}/tests/test_wire_decode_failed_prefix_constant_used_by_dialect.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: sqlalchemy-dqlite
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: SQLAlchemy 2.0 dialect for dqlite distributed SQLite
5
5
  Project-URL: Homepage, https://github.com/letsdiscodev/sqlalchemy-dqlite
6
6
  Project-URL: Repository, https://github.com/letsdiscodev/sqlalchemy-dqlite
@@ -22,9 +22,9 @@ Classifier: Topic :: Database :: Database Engines/Servers
22
22
  Classifier: Topic :: Database :: Front-Ends
23
23
  Classifier: Typing :: Typed
24
24
  Requires-Python: >=3.13
25
- Requires-Dist: dqlite-client<0.4.0,>=0.3.0
26
- Requires-Dist: dqlite-dbapi<0.4.0,>=0.3.0
27
- Requires-Dist: dqlite-wire<0.4.0,>=0.3.0
25
+ Requires-Dist: dqlite-client<0.5.0,>=0.4.0
26
+ Requires-Dist: dqlite-dbapi<0.5.0,>=0.4.0
27
+ Requires-Dist: dqlite-wire<0.5.0,>=0.4.0
28
28
  Requires-Dist: sqlalchemy<3.0,>=2.0
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: mypy>=1.0; extra == 'dev'
@@ -24,6 +24,24 @@ with engine.begin() as conn:
24
24
  The same applies to `engine.connect()`: SQLAlchemy auto-begins on the first
25
25
  execute, so a user-issued `text("BEGIN")` collides the same way.
26
26
 
27
+ ## Session modes
28
+
29
+ The dialect emits a bare `BEGIN`; the dbapi qualifies it according to the
30
+ connection's session mode (`BEGIN IMMEDIATE` by default, so a read-then-write
31
+ block cannot lose its snapshot to a concurrent writer). The engine-wide default
32
+ comes from the `session_mode` connect argument (`?session_mode=` in the URL or
33
+ `connect_args`); a per-connection override is the `dqlite_session_mode`
34
+ execution option:
35
+
36
+ ```python
37
+ with engine.connect().execution_options(dqlite_session_mode="read_only") as conn:
38
+ conn.execute(text("SELECT ...")) # writes raise OperationalError here
39
+ ```
40
+
41
+ Accepted values are `immediate`, `deferred`, `exclusive`, and `read_only`.
42
+ The option is transactional: it cannot be changed inside an open transaction,
43
+ and the pool restores the connect-time default on checkin.
44
+
27
45
  ## No `AUTOCOMMIT`
28
46
 
29
47
  `isolation_level="AUTOCOMMIT"` is rejected. Every dqlite statement goes
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sqlalchemy-dqlite"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "SQLAlchemy 2.0 dialect for dqlite distributed SQLite"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -26,15 +26,15 @@ classifiers = [
26
26
  "Typing :: Typed",
27
27
  ]
28
28
  dependencies = [
29
- "dqlite-dbapi>=0.3.0,<0.4.0",
29
+ "dqlite-dbapi>=0.4.0,<0.5.0",
30
30
  # The SA dialect imports dqliteclient and dqlitewire directly
31
31
  # (base.py / aio.py reach into client exception classes for
32
32
  # is_disconnect, and into dqlitewire for shared helpers). Pin
33
33
  # both transitively so a future major-version bump in either
34
34
  # package surfaces at install time, not at module-import time
35
35
  # in user code.
36
- "dqlite-client>=0.3.0,<0.4.0",
37
- "dqlite-wire>=0.3.0,<0.4.0",
36
+ "dqlite-client>=0.4.0,<0.5.0",
37
+ "dqlite-wire>=0.4.0,<0.5.0",
38
38
  "sqlalchemy>=2.0,<3.0",
39
39
  ]
40
40
 
@@ -27,7 +27,7 @@ from sqlalchemy.dialects.sqlite import (
27
27
  from sqlalchemydqlite.aio import DqliteDialect_aio
28
28
  from sqlalchemydqlite.base import DqliteCompiler, DqliteDialect
29
29
 
30
- __version__: _Final[str] = "0.3.0"
30
+ __version__: _Final[str] = "0.4.0"
31
31
 
32
32
  # SA convention: every shipped dialect package exposes ``<package>.dialect``
33
33
  # pointing at the default sync class.
@@ -18,6 +18,7 @@ from sqlalchemy.engine import characteristics as _sa_characteristics
18
18
  from sqlalchemy.engine.interfaces import BindTyping, DBAPIConnection, IsolationLevel
19
19
  from sqlalchemy.exc import ArgumentError
20
20
  from sqlalchemy.sql.compiler import InsertmanyvaluesSentinelOpts
21
+ from sqlalchemy.util import await_only
21
22
 
22
23
  import dqliteclient.exceptions as _client_exc
23
24
  import dqlitedbapi.exceptions as _dbapi_exc
@@ -357,9 +358,9 @@ class _DqliteDateTime(sqltypes.DateTime):
357
358
  f"DateTime bind: tzinfo {value.tzinfo!r} returned "
358
359
  f"None from utcoffset(); cannot serialise."
359
360
  )
360
- from dqlitedbapi.types import _format_utc_offset
361
+ from dqlitedbapi.types import format_utc_offset
361
362
 
362
- return base + _format_utc_offset(offset)
363
+ return base + format_utc_offset(offset)
363
364
  return value
364
365
 
365
366
  return process
@@ -587,9 +588,9 @@ class _DqliteTime(sqltypes.Time):
587
588
  f"returned None from utcoffset(); cannot "
588
589
  f"serialise without a resolvable offset."
589
590
  )
590
- from dqlitedbapi.types import _format_utc_offset
591
+ from dqlitedbapi.types import format_utc_offset
591
592
 
592
- return base + _format_utc_offset(offset)
593
+ return base + format_utc_offset(offset)
593
594
  return value
594
595
 
595
596
  return process
@@ -612,9 +613,9 @@ class _DqliteTime(sqltypes.Time):
612
613
  offset = value.utcoffset()
613
614
  if offset is None:
614
615
  return f"'{base}'"
615
- from dqlitedbapi.types import _format_utc_offset
616
+ from dqlitedbapi.types import format_utc_offset
616
617
 
617
- return f"'{base + _format_utc_offset(offset)}'"
618
+ return f"'{base + format_utc_offset(offset)}'"
618
619
 
619
620
  return process
620
621
 
@@ -723,50 +724,28 @@ class DqliteCompiler(SQLiteCompiler):
723
724
  class DqliteSessionModeCharacteristic(_sa_characteristics.ConnectionCharacteristic):
724
725
  """Per-connection ``dqlite_session_mode`` characteristic.
725
726
 
726
- Stores the mode on the underlying dqlitedbapi connection (unwrapped via
727
- ``_unwrap_dqlite_connection``) so ``do_begin`` and the cursor BEGIN-rewrite
728
- see it. ``transactional = True`` so mid-transaction toggles raise. Emits
729
- ``PRAGMA query_only = N`` only when crossing the read_only boundary, before
730
- updating the live attribute; force-closes the slot if the PRAGMA raises.
727
+ Delegates to the dbapi connection's ``session_mode`` / ``set_session_mode()``
728
+ (unwrapped via ``_unwrap_dqlite_connection``), which owns the ``PRAGMA query_only``
729
+ emission and the BEGIN rewrite. ``transactional = True`` so mid-transaction toggles
730
+ raise.
731
731
  """
732
732
 
733
733
  transactional: ClassVar[bool] = True
734
734
 
735
735
  def get_characteristic(self, dialect: Any, dbapi_conn: Any) -> str:
736
736
  target = dialect._unwrap_dqlite_connection(dbapi_conn)
737
- return getattr(target, "_dqlite_session_mode", "immediate")
737
+ return str(getattr(target, "session_mode", "immediate"))
738
738
 
739
739
  def set_characteristic(self, dialect: Any, dbapi_conn: Any, value: Any) -> None:
740
740
  target = dialect._unwrap_dqlite_connection(dbapi_conn)
741
741
  requested = dialect._validate_dqlite_session_mode(value)
742
- current = getattr(target, "_dqlite_session_mode", "immediate")
743
- if current == requested:
744
- return
745
- need_query_only = 1 if requested == "read_only" else 0
746
- was_query_only = 1 if current == "read_only" else 0
747
- try:
748
- if need_query_only != was_query_only:
749
- # Emit on the SA-side dbapi cursor (async routes through the
750
- # AsyncAdapt cursor under greenlet_spawn).
751
- cur = dbapi_conn.cursor()
752
- try:
753
- cur.execute(f"PRAGMA query_only = {need_query_only}")
754
- finally:
755
- cur.close()
756
- except BaseException:
757
- # Don't return a poisoned slot to the pool; suppress force-close's own
758
- # exceptions so the originating one propagates and SA invalidates.
759
- with contextlib.suppress(Exception):
760
- target.force_close_transport()
761
- raise
762
- target._dqlite_session_mode = requested
742
+ result = target.set_session_mode(requested)
743
+ if inspect.isawaitable(result):
744
+ await_only(result)
763
745
 
764
746
  def reset_characteristic(self, dialect: Any, dbapi_conn: Any) -> None:
765
- # SA's reset passes no "before" value; restore the construct-time default
766
- # captured once on ``_dqlite_session_mode_default``.
767
747
  target = dialect._unwrap_dqlite_connection(dbapi_conn)
768
- default = getattr(target, "_dqlite_session_mode_default", "immediate")
769
- self.set_characteristic(dialect, dbapi_conn, default)
748
+ self.set_characteristic(dialect, dbapi_conn, target.default_session_mode)
770
749
 
771
750
 
772
751
  class DqliteDialect(SQLiteDialect_pysqlite):
@@ -1378,36 +1357,18 @@ class DqliteDialect(SQLiteDialect_pysqlite):
1378
1357
  # pipeline which already classifies exceptions): do NOT mirror this raw-cursor
1379
1358
  # shape there.
1380
1359
  def do_begin(self, dbapi_connection: DBAPIConnection) -> None:
1381
- target = self._unwrap_dqlite_connection(dbapi_connection)
1382
- # Honour only a known str literal; any other shape (test MagicMock, etc.)
1383
- # falls back to "immediate" — do_begin is the wrong place to surface misuse
1384
- # (validation already ran at execution_options time).
1385
- raw_mode = getattr(target, "_dqlite_session_mode", "immediate")
1386
- mode = raw_mode.lower() if isinstance(raw_mode, str) and raw_mode else "immediate"
1387
- if mode in ("deferred", "read_only"):
1388
- # read_only rides DEFERRED (its PRAGMA query_only blocks writes); emit
1389
- # the explicit literal so the contract is visible at the SA layer too.
1390
- begin_sql = "BEGIN DEFERRED"
1391
- elif mode == "exclusive":
1392
- begin_sql = "BEGIN EXCLUSIVE"
1393
- else:
1394
- # "immediate" and any unknown value: bare BEGIN. The dbapi rewrites to
1395
- # IMMEDIATE unless its engine-wide default (connect_args session_mode)
1396
- # is non-immediate, in which case bare BEGIN is sent verbatim.
1397
- begin_sql = "BEGIN"
1360
+ # pysqlite's parent is a no-op because stdlib auto-BEGINs; dqlite has no
1361
+ # auto-BEGIN, so emit one. The dbapi qualifies it per the connection's
1362
+ # session mode (IMMEDIATE by default).
1398
1363
  cursor = dbapi_connection.cursor()
1399
1364
  try:
1400
- cursor.execute(begin_sql)
1365
+ cursor.execute("BEGIN")
1401
1366
  finally:
1402
1367
  # Guard close so a transport-class failure doesn't replace the
1403
- # propagating BEGIN exception (Python's finally-replaces rule) — SA's
1404
- # wrapping must see the BEGIN error directly, not as __context__.
1368
+ # propagating BEGIN exception (Python's finally-replaces rule).
1405
1369
  try:
1406
1370
  cursor.close()
1407
1371
  except _FORCE_CLOSE_TAIL_EXCEPTIONS:
1408
- # Wider tuple (matching do_close) so cross-loop RuntimeError /
1409
- # dead-proxy ReferenceError don't escape and mask the BEGIN error;
1410
- # programmer-bug shapes still escape.
1411
1372
  logger.debug(
1412
1373
  "do_begin: cursor.close failed after BEGIN; BEGIN exception preserved",
1413
1374
  exc_info=True,
@@ -384,8 +384,7 @@ class Requirements(SuiteRequirements):
384
384
 
385
385
  @property
386
386
  def fetch_first(self) -> compound:
387
- """Closed: SA's compiler emits LIMIT/OFFSET for SQLite, so these tests
388
- never actually exercise FETCH FIRST."""
387
+ """SQLite has no ``FETCH FIRST ... ROWS ONLY`` syntax, only LIMIT/OFFSET."""
389
388
  return exclusions.closed()
390
389
 
391
390
  @property
@@ -8,20 +8,6 @@ from pathlib import Path
8
8
  import pytest
9
9
 
10
10
 
11
- @pytest.fixture(autouse=True)
12
- def _clear_resolve_leader_cache() -> Iterator[None]:
13
- """Clear the process-wide ``_RESOLVE_LEADER_CACHE`` between tests.
14
-
15
- Without this, two SA tests targeting the same (address, governors) via
16
- different ClusterClient mocks would share a stale cached instance.
17
- """
18
- from dqlitedbapi import connection as _conn_mod
19
-
20
- _conn_mod._RESOLVE_LEADER_CACHE.clear()
21
- yield
22
- _conn_mod._RESOLVE_LEADER_CACHE.clear()
23
-
24
-
25
11
  @pytest.fixture(autouse=True)
26
12
  def _reset_unparseable_iso_warning_gate() -> Iterator[None]:
27
13
  """Reset each type-class's one-shot ``_unparseable_iso_warning_emitted``
@@ -68,7 +68,7 @@ def test_stale_rows_cleared_when_execute_raises(monkeypatch: pytest.MonkeyPatch)
68
68
 
69
69
  adapter = AsyncAdaptedCursor(conn_adapter)
70
70
  # Seed stale state simulating a prior successful execute.
71
- adapter.description = [("a", None, None, None, None, None, None)]
71
+ adapter.description = [("a", 3, None, None, None, None, None)]
72
72
  adapter._rows = deque([(1,), (2,)])
73
73
  adapter.rowcount = 2
74
74
  adapter.lastrowid = 10
@@ -104,7 +104,7 @@ def test_stale_rows_cleared_when_executemany_raises(
104
104
  )
105
105
 
106
106
  adapter = AsyncAdaptedCursor(conn_adapter) # type: ignore[arg-type]
107
- adapter.description = [("a", None, None, None, None, None, None)]
107
+ adapter.description = [("a", 3, None, None, None, None, None)]
108
108
  adapter._rows = deque([(1,)])
109
109
  adapter.rowcount = 3
110
110
  adapter.lastrowid = 99
@@ -61,7 +61,7 @@ class TestAsyncAdaptedCursorSoftCloseNoop:
61
61
  adapted_conn._connection = underlying
62
62
  cur = AsyncAdaptedCursor(adapted_conn)
63
63
  cur._rows = deque([(1,), (2,)])
64
- cur.description = (("col", None, None, None, None, None, None),)
64
+ cur.description = (("col", 3, None, None, None, None, None),)
65
65
  cur.rowcount = 2
66
66
  cur.lastrowid = None
67
67
 
@@ -76,5 +76,5 @@ class TestAsyncAdaptedCursorSoftCloseNoop:
76
76
  # Cursor state unchanged — soft-close is documentary, not destructive.
77
77
  assert cur._rows == deque([(1,), (2,)])
78
78
  assert cur.rowcount == 2
79
- assert cur.description == (("col", None, None, None, None, None, None),)
79
+ assert cur.description == (("col", 3, None, None, None, None, None),)
80
80
  assert cur._closed is False
@@ -11,10 +11,8 @@ from sqlalchemy.exc import ArgumentError
11
11
  from sqlalchemydqlite.aio import DqliteDialect_aio
12
12
 
13
13
 
14
- @pytest.mark.parametrize("bogus", [42, "string", object(), None, [1, 2]])
14
+ @pytest.mark.parametrize("bogus", [42, "string", object(), [1, 2]])
15
15
  def test_async_creator_fn_noncallable_raises_argument_error(bogus: Any) -> None:
16
- if bogus is None:
17
- pytest.skip("None means 'no creator_fn'; the gate correctly does not raise.")
18
16
  dialect = DqliteDialect_aio()
19
17
  with pytest.raises(ArgumentError, match="async_creator_fn"):
20
18
  dialect.connect(async_creator_fn=bogus)
@@ -33,7 +33,7 @@ def test_executemany_on_closed_cursor_raises() -> None:
33
33
 
34
34
  def test_close_clears_result_set_but_preserves_rowcount_lastrowid() -> None:
35
35
  cur = _make_cursor()
36
- cur.description = (("col", None, None, None, None, None, None),)
36
+ cur.description = (("col", 3, None, None, None, None, None),)
37
37
  cur.rowcount = 42
38
38
  cur.lastrowid = 7
39
39
  cur._rows.append((1,))
@@ -80,7 +80,7 @@ class TestAsyncExecutemanyLeaderFlipResetState:
80
80
  cur = _make_adapted_cursor(underlying)
81
81
 
82
82
  # Pre-populate state so the up-front reset is observable.
83
- cur.description = [("col", None, None, None, None, None, None)]
83
+ cur.description = [("col", 3, None, None, None, None, None)]
84
84
  cur.rowcount = 99
85
85
  cur.lastrowid = 42
86
86
  cur._rows.extend([(1,), (2,)])
@@ -41,11 +41,11 @@ class TestDetectAutocommitSetting:
41
41
  the value SA's probe keys on. Pin the value, not just the descriptor."""
42
42
  from dqlitedbapi.connection import Connection as DqliteSyncConnection
43
43
 
44
- instance_unused = DqliteSyncConnection.__new__(DqliteSyncConnection)
45
- # The getter raises InterfaceError on a closed connection; __new__ skips
46
- # __init__, so set _closed explicitly to reach the property body.
47
- instance_unused._closed = False
48
- assert instance_unused.isolation_level is None
44
+ conn = DqliteSyncConnection("localhost:19001")
45
+ try:
46
+ assert conn.isolation_level is None
47
+ finally:
48
+ conn.close()
49
49
 
50
50
  def test_async_dbapi_connection_isolation_level_also_returns_none(self) -> None:
51
51
  """Sibling pin on the async surface."""
@@ -53,10 +53,7 @@ class TestDetectAutocommitSetting:
53
53
  AsyncConnection as DqliteAsyncConnection,
54
54
  )
55
55
 
56
- instance_unused = DqliteAsyncConnection.__new__(DqliteAsyncConnection)
57
- # See sync sibling: _closed must be set before the property fires.
58
- instance_unused._closed = False
59
- assert instance_unused.isolation_level is None
56
+ assert DqliteAsyncConnection("localhost:19001").isolation_level is None
60
57
 
61
58
  def test_override_remains_load_bearing_against_isolation_level_eq_none(self) -> None:
62
59
  """The override returns False even when the probe sees isolation_level is None."""
@@ -287,11 +287,17 @@ class TestURLGovernorsReachAioDbapi:
287
287
  )
288
288
  _, kwargs = dialect.create_connect_args(url)
289
289
  aio_module = DqliteDialect_aio.import_dbapi()
290
+ # A dropped or renamed knob would raise TypeError here.
290
291
  conn = aio_module.connect(**kwargs)
291
- assert conn._max_total_rows == 500
292
- assert conn._max_continuation_frames == 7
293
- assert conn._trust_server_heartbeat is True
294
- assert conn._timeout == 5
292
+ assert conn.max_total_rows == 500
293
+ assert kwargs == {
294
+ "address": "host:19001",
295
+ "database": "db",
296
+ "timeout": 5.0,
297
+ "max_total_rows": 500,
298
+ "max_continuation_frames": 7,
299
+ "trust_server_heartbeat": True,
300
+ }
295
301
 
296
302
 
297
303
  class TestDoPingNarrowExceptions:
@@ -82,7 +82,7 @@ wheels = [
82
82
 
83
83
  [[package]]
84
84
  name = "dqlite-client"
85
- version = "0.3.0"
85
+ version = "0.4.0"
86
86
  source = { editable = "../python-dqlite-client" }
87
87
  dependencies = [
88
88
  { name = "dqlite-wire" },
@@ -104,7 +104,7 @@ provides-extras = ["dev", "yaml-store"]
104
104
 
105
105
  [[package]]
106
106
  name = "dqlite-dbapi"
107
- version = "0.3.0"
107
+ version = "0.4.0"
108
108
  source = { editable = "../python-dqlite-dbapi" }
109
109
  dependencies = [
110
110
  { name = "dqlite-client" },
@@ -125,7 +125,7 @@ provides-extras = ["dev"]
125
125
 
126
126
  [[package]]
127
127
  name = "dqlite-wire"
128
- version = "0.3.0"
128
+ version = "0.4.0"
129
129
  source = { editable = "../python-dqlite-wire" }
130
130
 
131
131
  [package.metadata]
@@ -413,7 +413,7 @@ wheels = [
413
413
 
414
414
  [[package]]
415
415
  name = "sqlalchemy-dqlite"
416
- version = "0.3.0"
416
+ version = "0.4.0"
417
417
  source = { editable = "." }
418
418
  dependencies = [
419
419
  { name = "dqlite-client" },