iris-devtester 1.19.0__tar.gz → 1.19.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 (271) hide show
  1. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/CHANGELOG.md +18 -0
  2. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/CLAUDE.md +16 -0
  3. {iris_devtester-1.19.0/iris_devtester.egg-info → iris_devtester-1.19.2}/PKG-INFO +1 -1
  4. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/__init__.py +1 -1
  5. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/dbapi_compat.py +40 -7
  6. {iris_devtester-1.19.0 → iris_devtester-1.19.2/iris_devtester.egg-info}/PKG-INFO +1 -1
  7. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester.egg-info/SOURCES.txt +1 -0
  8. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/pyproject.toml +1 -1
  9. iris_devtester-1.19.2/tests/unit/utils/test_dbapi_compat.py +183 -0
  10. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/AGENTS.md +0 -0
  11. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/CONSTITUTION.md +0 -0
  12. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/LICENSE +0 -0
  13. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/MANIFEST.in +0 -0
  14. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/README.md +0 -0
  15. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/GETTING_STARTED.md +0 -0
  16. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/LANGCHAIN_INTEGRATION_QUICKSTART.md +0 -0
  17. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/ROADMAP.md +0 -0
  18. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/SQL_VS_OBJECTSCRIPT.md +0 -0
  19. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/TROUBLESHOOTING.md +0 -0
  20. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/WHATS_NEW_v1.4.0.md +0 -0
  21. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/AGENTIC_SANDBOX_ENHANCEMENT_REPORT.md +0 -0
  22. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/IMPACT_ANALYSIS.md +0 -0
  23. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/IRIS_DEVTESTER_POSITIONING_REPORT.md +0 -0
  24. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/LANGCHAIN_INTEGRATION_STRATEGY.md +0 -0
  25. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/LANGCHAIN_INTEGRATION_TEST_RESULTS.md +0 -0
  26. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/PHASE_2_PLAN.md +0 -0
  27. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/RAG_TEMPLATES_ANALYSIS.md +0 -0
  28. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/README.md +0 -0
  29. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/STRATEGIC_ROADMAP_SUMMARY.md +0 -0
  30. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/archive/feature-009-refactor-plan.md +0 -0
  31. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/BUG_REPORT.md +0 -0
  32. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/EXTRACTION_SUMMARY.md +0 -0
  33. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/FEATURE_006_SUMMARY.md +0 -0
  34. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/PHASE2_RESULTS.md +0 -0
  35. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/PRE_PUBLISH_REVIEW.md +0 -0
  36. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/PROGRESS.md +0 -0
  37. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/PYPI_READINESS.md +0 -0
  38. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/SESSION-INTEGRATION-TESTS.md +0 -0
  39. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/SESSION-SUMMARY.md +0 -0
  40. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/STATUS-002-PIVOTED.md +0 -0
  41. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/STATUS-003-COMPLETE.md +0 -0
  42. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/STATUS.md +0 -0
  43. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/V1_COMPLETION_PLAN.md +0 -0
  44. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/development/V1_RELEASE_SUMMARY.md +0 -0
  45. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/WSGI-ASGI-SERVER-SETUP.md +0 -0
  46. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/agent-skills.md +0 -0
  47. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/dat-fixtures.md +0 -0
  48. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/docker-compose.md +0 -0
  49. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/performance-monitoring.md +0 -0
  50. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/features/testcontainers.md +0 -0
  51. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/api-contract-synchronization.md +0 -0
  52. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/callin-service-requirement.md +0 -0
  53. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/cpf-merge-and-container-restarts.md +0 -0
  54. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dat-fixtures-docker-exec-pattern.md +0 -0
  55. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dat-restore-database-isolation-problem.md +0 -0
  56. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dbapi-bulk-insert-performance-issue.md +0 -0
  57. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dbapi-objectscript-limitation.md +0 -0
  58. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dbapi-password-reset-limitation.md +0 -0
  59. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/dbapi-private-module-myth.md +0 -0
  60. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/docker-hub-image-naming.md +0 -0
  61. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/embedded-python-considerations.md +0 -0
  62. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/feature-002-pivot-summary.md +0 -0
  63. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/integration-test-dbapi-limitation.md +0 -0
  64. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-backup-patterns.md +0 -0
  65. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-connection-access-denied-bug.md +0 -0
  66. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-container-dind-port-mapping.md +0 -0
  67. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-container-graceful-shutdown.md +0 -0
  68. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-container-performance.md +0 -0
  69. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-container-readiness.md +0 -0
  70. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-container-volume-permissions.md +0 -0
  71. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-docker-sdk-environment-variables.md +0 -0
  72. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-performance-monitoring-landscape.md +0 -0
  73. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/iris-security-users-api.md +0 -0
  74. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/irishealth-editions.md +0 -0
  75. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/namespace-sql-vs-iris-connect.md +0 -0
  76. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/password-reset-changeflag-fix.md +0 -0
  77. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/rag-templates-production-patterns.md +0 -0
  78. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/sql-task-manager-operations.md +0 -0
  79. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/test-isolation-fix-summary.md +0 -0
  80. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/test-isolation-investigation.md +0 -0
  81. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/learnings/testcontainers-ryuk-lifecycle.md +0 -0
  82. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/docs/troubleshooting/table-not-found.md +0 -0
  83. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/01_quickstart.py +0 -0
  84. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/02_connection_management.py +0 -0
  85. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/04_pytest_fixtures.py +0 -0
  86. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/05_ci_cd.py +0 -0
  87. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/08_auto_discovery.py +0 -0
  88. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/09_enterprise.py +0 -0
  89. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/10_docker_compose_integration.py +0 -0
  90. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/examples/langchain_integration_example.py +0 -0
  91. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/__main__.py +0 -0
  92. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/__init__.py +0 -0
  93. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/__main__.py +0 -0
  94. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/connection_commands.py +0 -0
  95. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/container.py +0 -0
  96. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/container_commands.py +0 -0
  97. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/dev_commands.py +0 -0
  98. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/cli/fixture_commands.py +0 -0
  99. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/__init__.py +0 -0
  100. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/auto_discovery.py +0 -0
  101. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/container_config.py +0 -0
  102. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/container_state.py +0 -0
  103. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/defaults.py +0 -0
  104. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/discovery.py +0 -0
  105. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/models.py +0 -0
  106. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/presets.py +0 -0
  107. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/config/yaml_loader.py +0 -0
  108. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/__init__.py +0 -0
  109. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/auto_discovery.py +0 -0
  110. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/connection.py +0 -0
  111. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/cursor_wrapper.py +0 -0
  112. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/dbapi.py +0 -0
  113. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/jdbc.py +0 -0
  114. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/manager.py +0 -0
  115. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/models.py +0 -0
  116. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/connections/retry.py +0 -0
  117. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/__init__.py +0 -0
  118. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/connection_info.py +0 -0
  119. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/cpf_manager.py +0 -0
  120. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/dev_instance.py +0 -0
  121. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/iris_container.py +0 -0
  122. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/models.py +0 -0
  123. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/monitor_utils.py +0 -0
  124. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/monitoring.py +0 -0
  125. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/performance.py +0 -0
  126. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/validation.py +0 -0
  127. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/containers/wait_strategies.py +0 -0
  128. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/diagnostics.py +0 -0
  129. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/__init__.py +0 -0
  130. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/creator.py +0 -0
  131. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/loader.py +0 -0
  132. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/manifest.py +0 -0
  133. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/obj_export.py +0 -0
  134. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/fixtures/validator.py +0 -0
  135. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/integrations/__init__.py +0 -0
  136. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/integrations/langchain.py +0 -0
  137. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/ports/__init__.py +0 -0
  138. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/ports/assignment.py +0 -0
  139. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/ports/exceptions.py +0 -0
  140. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/ports/registry.py +0 -0
  141. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/testing/__init__.py +0 -0
  142. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/testing/fixtures.py +0 -0
  143. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/testing/helpers.py +0 -0
  144. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/testing/models.py +0 -0
  145. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/testing/schema_reset.py +0 -0
  146. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/__init__.py +0 -0
  147. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/container_port.py +0 -0
  148. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/container_status.py +0 -0
  149. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/enable_callin.py +0 -0
  150. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/health_checks.py +0 -0
  151. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/iris_container_adapter.py +0 -0
  152. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/namespace.py +0 -0
  153. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/password.py +0 -0
  154. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/progress.py +0 -0
  155. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester/utils/test_connection.py +0 -0
  156. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester.egg-info/dependency_links.txt +0 -0
  157. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester.egg-info/entry_points.txt +0 -0
  158. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester.egg-info/requires.txt +0 -0
  159. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/iris_devtester.egg-info/top_level.txt +0 -0
  160. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/setup.cfg +0 -0
  161. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/__init__.py +0 -0
  162. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/conftest.py +0 -0
  163. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/__init__.py +0 -0
  164. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_logs_contract.py +0 -0
  165. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_remove_contract.py +0 -0
  166. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_restart_contract.py +0 -0
  167. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_start_contract.py +0 -0
  168. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_status_contract.py +0 -0
  169. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_stop_contract.py +0 -0
  170. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/cli/test_container_up_contract.py +0 -0
  171. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_031_diagnostics.py +0 -0
  172. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_032_health_check.py +0 -0
  173. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_033_health_editions.py +0 -0
  174. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_034_cpf_password.py +0 -0
  175. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_035_graceful_shutdown.py +0 -0
  176. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_agent_skills.py +0 -0
  177. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_cli_container_commands.py +0 -0
  178. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_cli_fixture_commands.py +0 -0
  179. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_cli_ux_contract.py +0 -0
  180. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_connection_api.py +0 -0
  181. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_container_api.py +0 -0
  182. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_container_integration_contract.py +0 -0
  183. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_container_status_api.py +0 -0
  184. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_container_validation_api.py +0 -0
  185. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_dind_port_mapping.py +0 -0
  186. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_enable_callin_api.py +0 -0
  187. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_fixture_creator_api.py +0 -0
  188. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_fixture_loader_api.py +0 -0
  189. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_fixture_validator_api.py +0 -0
  190. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_iriscontainer_attach.py +0 -0
  191. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_legacy_package_contract.py +0 -0
  192. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_modern_package_contract.py +0 -0
  193. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_monitoring_config_api.py +0 -0
  194. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_package_detection.py +0 -0
  195. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_port_registry_contract.py +0 -0
  196. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_preconfig_contract.py +0 -0
  197. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_reset_verification_contract.py +0 -0
  198. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_resource_monitoring_api.py +0 -0
  199. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_retry_logic_contract.py +0 -0
  200. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_task_manager_api.py +0 -0
  201. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_test_connection_api.py +0 -0
  202. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/contract/test_testing_fixtures_api.py +0 -0
  203. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/e2e/__init__.py +0 -0
  204. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/e2e/test_port_registry_e2e.py +0 -0
  205. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/e2e/test_skill_workflow.py +0 -0
  206. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/__init__.py +0 -0
  207. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/conftest.py +0 -0
  208. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/__init__.py +0 -0
  209. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/test_manual_port_override.py +0 -0
  210. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/test_multi_project_isolation.py +0 -0
  211. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/test_port_exhaustion.py +0 -0
  212. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/test_port_persistence.py +0 -0
  213. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/ports/test_stale_cleanup.py +0 -0
  214. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_bug_fixes.py +0 -0
  215. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_bug_fixes_011.py +0 -0
  216. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_cli_container_integration.py +0 -0
  217. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_connection_info_integration.py +0 -0
  218. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_connection_integration.py +0 -0
  219. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_container_health_monitor.py +0 -0
  220. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_container_status_integration.py +0 -0
  221. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_container_validation.py +0 -0
  222. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_cpf_merge.py +0 -0
  223. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_cpf_presets.py +0 -0
  224. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_cpf_security.py +0 -0
  225. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_custom_user_remediation.py +0 -0
  226. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_dev_instance.py +0 -0
  227. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_enable_callin_integration.py +0 -0
  228. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_fixture_export_patterns.py +0 -0
  229. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_fixture_performance.py +0 -0
  230. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_fixture_refresh.py +0 -0
  231. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_fixtures_integration.py +0 -0
  232. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_implicit_namespace.py +0 -0
  233. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_iriscontainer_attach_integration.py +0 -0
  234. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_monitor_utils_integration.py +0 -0
  235. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_monitoring_integration.py +0 -0
  236. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_preconfig_integration.py +0 -0
  237. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_reset_both_editions.py +0 -0
  238. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_reset_integration.py +0 -0
  239. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_reset_macos.py +0 -0
  240. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_reset_timing.py +0 -0
  241. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_password_reset_validation.py +0 -0
  242. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_proactive_password_reset.py +0 -0
  243. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_real_world_problems.py +0 -0
  244. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_reliable_password_reset.py +0 -0
  245. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/integration/test_test_connection_integration.py +0 -0
  246. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/__init__.py +0 -0
  247. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/config/test_config_hierarchy.py +0 -0
  248. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/config/test_container_config.py +0 -0
  249. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/config/test_yaml_loader.py +0 -0
  250. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_auto_discovery.py +0 -0
  251. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_config_discovery.py +0 -0
  252. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_connection_fallback.py +0 -0
  253. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_connection_info.py +0 -0
  254. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_cpf_manager.py +0 -0
  255. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_dev_instance_logic.py +0 -0
  256. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_iris_config.py +0 -0
  257. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_iris_connection_info.py +0 -0
  258. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_iris_container.py +0 -0
  259. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_manifest.py +0 -0
  260. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_monitoring_policy.py +0 -0
  261. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_namespace_utils.py +0 -0
  262. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_password_preconfig.py +0 -0
  263. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_password_preconfig_unit.py +0 -0
  264. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_performance_metrics.py +0 -0
  265. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_resource_thresholds.py +0 -0
  266. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_retry.py +0 -0
  267. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_schema_models.py +0 -0
  268. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_schema_reset_logic.py +0 -0
  269. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_validation_results.py +0 -0
  270. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/test_wait_strategies.py +0 -0
  271. {iris_devtester-1.19.0 → iris_devtester-1.19.2}/tests/unit/utils/test_iris_container_adapter.py +0 -0
@@ -5,6 +5,22 @@ All notable changes to iris-devtester will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.19.2] - 2026-07-30 - Fix connect_function ImportError when module absent from sys.modules
9
+
10
+ ### Fixed
11
+
12
+ - **`DBAPIPackageInfo.connect_function` raises after `patch.dict` exit** (`utils/dbapi_compat.py`): `patch.dict(sys.modules, ...)` deletes keys that were absent before the patch when it exits — the common case for unit tests that mock `intersystems_iris` before it has been imported. The 1.19.1 `@property` resolved the MagicMock poisoning but left `sys.modules.get()` returning `None` in this scenario, raising `ImportError: IRIS DBAPI module 'intersystems_iris' is no longer in sys.modules`. The module was importable the whole time. Fixed by falling back to `importlib.import_module(import_path)` when `sys.modules.get()` returns `None`.
13
+
14
+ ## [1.19.1] - 2026-07-30 - Fix dbapi_compat singleton poisoning under test mocks
15
+
16
+ ### Fixed
17
+
18
+ - **`DBAPIConnectionAdapter` singleton mock poisoning** (`utils/dbapi_compat.py`): when a test patched `intersystems_iris` via `patch.dict(sys.modules, ...)` and the adapter singleton was first built during that patch, the adapter held a reference to the mock's `connect` function for the rest of the process — after `sys.modules` was fully restored. Downstream tests then silently operated against a `MagicMock` connection. Fixed by making `DBAPIPackageInfo.connect_function` a `@property` that resolves the function from `sys.modules` on every call instead of binding it at detection time. The per-call cost is a single `sys.modules` lookup and `getattr` — negligible against opening a socket.
19
+
20
+ ### Added
21
+
22
+ - **`dbapi_compat.reset_adapter()`**: public function to clear the singleton so tests can force re-detection after their patch exits. Previously the only workaround was reaching into the private `_adapter` global from `conftest.py`. Added to `__all__`.
23
+
8
24
  ## [1.19.0] - 2026-07-19 - iris-agentic-dev Handoff Contract + Discrete Skills
9
25
 
10
26
  ### Added
@@ -983,6 +999,7 @@ v1.4.3 added connection-based verification with retry logic, which is valuable f
983
999
  - `iris_devtester/utils/iris_container_adapter.py` (Docker SDK volume application)
984
1000
  - `iris_devtester/config/container_config.py` (validate_volume_paths method)
985
1001
  - **Example**:
1002
+
986
1003
  ```yaml
987
1004
  volumes:
988
1005
  - ./workspace:/external/workspace # Read-write
@@ -1087,6 +1104,7 @@ v1.4.3 added connection-based verification with retry logic, which is valuable f
1087
1104
  - **Impact**: Configuration-defined volumes now work correctly (previously ignored)
1088
1105
  - **Location**: `iris_devtester/utils/iris_container_adapter.py:52-58`
1089
1106
  - **Example**:
1107
+
1090
1108
  ```yaml
1091
1109
  volumes:
1092
1110
  - ./data:/external # Read-write mount
@@ -123,3 +123,19 @@ reset), 033 (health/ai_hub editions), 034 (CPF-first password strategy).
123
123
 
124
124
  `~/ws/rag-templates/` contains original production code this was extracted from. Consult
125
125
  it when the current implementation is unclear — especially `common/iris_connection_manager.py`.
126
+
127
+ <!-- codebase-memory-mcp: Code Discovery Protocol -->
128
+ ## Code Discovery Protocol (codebase-memory-mcp)
129
+
130
+ **ALWAYS use `codebase-memory-mcp` tools FIRST for any code exploration:**
131
+
132
+ - `search_graph(name_pattern/label/qn_pattern)` — find functions, classes, routes
133
+ - `trace_path(function_name, mode=calls|data_flow|cross_service)` — call chains
134
+ - `get_code_snippet(qualified_name)` — exact symbol source with precise line ranges
135
+ - `query_graph(query)` — complex Cypher patterns across the codebase graph
136
+ - `get_architecture(aspects)` — project structure overview
137
+ - `search_code(pattern)` — graph-augmented text search
138
+
139
+ Use `Grep`/`Glob`/`Read` freely for text, configs, and non-code files, and always
140
+ `Read` a file before editing it. If the project is not indexed yet, run
141
+ `index_repository` first.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris-devtester
3
- Version: 1.19.0
3
+ Version: 1.19.2
4
4
  Summary: Battle-tested InterSystems IRIS infrastructure utilities for Python development
5
5
  Author-email: InterSystems Community <community@intersystems.com>
6
6
  Maintainer-email: Thomas Dyar <thomas.dyar@intersystems.com>
@@ -26,7 +26,7 @@ LangChain Integration:
26
26
  ... # Build your RAG app...
27
27
  """
28
28
 
29
- __version__ = "1.19.0"
29
+ __version__ = "1.19.2"
30
30
  __author__ = "InterSystems Community"
31
31
  __license__ = "MIT"
32
32
 
@@ -29,9 +29,10 @@ Logging Levels:
29
29
 
30
30
  import importlib.metadata
31
31
  import logging
32
+ import sys
32
33
  import time
33
34
  from dataclasses import dataclass
34
- from typing import Any, Callable, Optional
35
+ from typing import Any, Optional
35
36
 
36
37
  from packaging import version
37
38
 
@@ -45,18 +46,38 @@ class DBAPIPackageInfo:
45
46
 
46
47
  Attributes:
47
48
  package_name: One of "intersystems-irispython" or "intersystems-iris"
48
- import_path: Module import path (e.g., "intersystems_iris.dbapi._DBAPI")
49
+ import_path: Module import path (e.g., "intersystems_iris")
49
50
  version: Package version (e.g., "5.3.0")
50
- connect_function: Reference to the connect() function
51
+ connect_attr: Attribute name of the connect function on the module (usually "connect")
51
52
  detection_time_ms: Time taken to detect package in milliseconds
52
53
  """
53
54
 
54
55
  package_name: str
55
56
  import_path: str
56
57
  version: str
57
- connect_function: Callable[..., Any]
58
+ connect_attr: str
58
59
  detection_time_ms: float
59
60
 
61
+ @property
62
+ def connect_function(self) -> Any:
63
+ """Resolve connect function live from sys.modules on every access.
64
+
65
+ Resolving at call time (not at detection time) ensures that test patches
66
+ applied via patch.dict(sys.modules, ...) take effect for exactly the
67
+ duration of the patch and do not poison the singleton after the patch exits.
68
+
69
+ patch.dict removes keys that were absent before the patch, so after exit
70
+ the module may be gone from sys.modules even though it is importable.
71
+ Fall back to importlib.import_module() in that case rather than raising.
72
+ See IDT-BUG-dbapi-adapter-singleton.md.
73
+ """
74
+ import importlib
75
+
76
+ module = sys.modules.get(self.import_path)
77
+ if module is None:
78
+ module = importlib.import_module(self.import_path)
79
+ return getattr(module, self.connect_attr)
80
+
60
81
 
61
82
  def validate_package_version(package_name: str, installed_version: str, min_version: str) -> None:
62
83
  """Validate that installed package meets minimum version requirement.
@@ -154,7 +175,7 @@ def detect_dbapi_package() -> DBAPIPackageInfo:
154
175
  package_name="intersystems-irispython",
155
176
  import_path="intersystems_iris",
156
177
  version=pkg_version,
157
- connect_function=intersystems_iris.connect,
178
+ connect_attr="connect",
158
179
  detection_time_ms=elapsed_ms,
159
180
  )
160
181
  except (ImportError, importlib.metadata.PackageNotFoundError):
@@ -220,7 +241,7 @@ def detect_dbapi_package() -> DBAPIPackageInfo:
220
241
  package_name="intersystems-irispython",
221
242
  import_path="iris",
222
243
  version=pkg_version,
223
- connect_function=iris.connect,
244
+ connect_attr="connect",
224
245
  detection_time_ms=elapsed_ms,
225
246
  )
226
247
 
@@ -239,7 +260,7 @@ def detect_dbapi_package() -> DBAPIPackageInfo:
239
260
  package_name="intersystems-iris",
240
261
  import_path="iris.irissdk",
241
262
  version=pkg_version,
242
- connect_function=iris.irissdk.connect,
263
+ connect_attr="connect",
243
264
  detection_time_ms=elapsed_ms,
244
265
  )
245
266
  except ImportError:
@@ -314,6 +335,17 @@ def _get_adapter() -> DBAPIConnectionAdapter:
314
335
  return _adapter
315
336
 
316
337
 
338
+ def reset_adapter() -> None:
339
+ """Clear the singleton adapter so it is re-detected on next use.
340
+
341
+ Intended for test teardown. Allows tests that patch sys.modules to restore
342
+ a clean adapter after their patch exits, without reaching into private globals.
343
+ See IDT-BUG-dbapi-adapter-singleton.md.
344
+ """
345
+ global _adapter
346
+ _adapter = None
347
+
348
+
317
349
  def get_connection(*args, **kwargs) -> Any:
318
350
  """Get DBAPI connection using detected package.
319
351
 
@@ -354,4 +386,5 @@ __all__ = [
354
386
  "DBAPIConnectionAdapter",
355
387
  "get_connection",
356
388
  "get_package_info",
389
+ "reset_adapter",
357
390
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris-devtester
3
- Version: 1.19.0
3
+ Version: 1.19.2
4
4
  Summary: Battle-tested InterSystems IRIS infrastructure utilities for Python development
5
5
  Author-email: InterSystems Community <community@intersystems.com>
6
6
  Maintainer-email: Thomas Dyar <thomas.dyar@intersystems.com>
@@ -265,4 +265,5 @@ tests/unit/test_wait_strategies.py
265
265
  tests/unit/config/test_config_hierarchy.py
266
266
  tests/unit/config/test_container_config.py
267
267
  tests/unit/config/test_yaml_loader.py
268
+ tests/unit/utils/test_dbapi_compat.py
268
269
  tests/unit/utils/test_iris_container_adapter.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iris-devtester"
7
- version = "1.19.0"
7
+ version = "1.19.2"
8
8
  description = "Battle-tested InterSystems IRIS infrastructure utilities for Python development"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -0,0 +1,183 @@
1
+ """Tests for dbapi_compat singleton-poisoning fix.
2
+
3
+ Verifies that mocking intersystems_iris does not permanently poison the
4
+ DBAPIConnectionAdapter singleton — the core defect reported in
5
+ IDT-BUG-dbapi-adapter-singleton.md.
6
+ """
7
+
8
+ import sys
9
+ from unittest.mock import MagicMock, patch
10
+
11
+ import pytest
12
+
13
+ import iris_devtester.utils.dbapi_compat as dc
14
+
15
+
16
+ @pytest.fixture(autouse=True)
17
+ def reset_adapter():
18
+ """Ensure each test starts with a clean adapter."""
19
+ dc.reset_adapter()
20
+ yield
21
+ dc.reset_adapter()
22
+
23
+
24
+ class TestModuleAbsentAfterPatch:
25
+ """patch.dict removes keys that were absent before the patch on exit.
26
+
27
+ The module is importable but not in sys.modules. connect_function must
28
+ import it rather than raising ImportError.
29
+ """
30
+
31
+ def test_connect_function_importable_when_absent_from_sys_modules(self):
32
+ """If import_path was absent pre-patch, it's deleted post-patch; must still resolve."""
33
+ import importlib
34
+
35
+ # Ensure the module is absent from sys.modules, then mock it
36
+ real_module = sys.modules.pop("intersystems_iris", None)
37
+ fake = MagicMock()
38
+ fake.connect = object() # sentinel
39
+
40
+ try:
41
+ assert "intersystems_iris" not in sys.modules, "pre-condition: key must be absent"
42
+ with patch.dict(sys.modules, {"intersystems_iris": fake}):
43
+ dc.reset_adapter()
44
+ dc.get_package_info() # singleton built while mock is present
45
+
46
+ # After patch.dict exit the key is gone (was absent before)
47
+ assert "intersystems_iris" not in sys.modules
48
+
49
+ # connect_function must import the real module, not raise
50
+ info = dc.get_package_info()
51
+ # Should not raise; real module is importable
52
+ fn = info.connect_function
53
+ assert not isinstance(fn, MagicMock), (
54
+ "connect_function returned MagicMock after patch exit with absent key"
55
+ )
56
+ finally:
57
+ # Restore original state
58
+ if real_module is not None:
59
+ sys.modules["intersystems_iris"] = real_module
60
+ elif "intersystems_iris" in sys.modules:
61
+ del sys.modules["intersystems_iris"]
62
+
63
+ def test_connect_function_does_not_raise_when_module_absent_from_sys_modules(self):
64
+ """connect_function must not raise ImportError when module absent but importable."""
65
+ import importlib
66
+
67
+ real_module = sys.modules.pop("intersystems_iris", None)
68
+ fake = MagicMock()
69
+ fake.connect = MagicMock()
70
+
71
+ try:
72
+ with patch.dict(sys.modules, {"intersystems_iris": fake}):
73
+ dc.reset_adapter()
74
+ info = dc.get_package_info()
75
+
76
+ assert "intersystems_iris" not in sys.modules
77
+
78
+ # Must not raise
79
+ dc.reset_adapter()
80
+ try:
81
+ info2 = dc.get_package_info()
82
+ _ = info2.connect_function
83
+ except ImportError as e:
84
+ pytest.fail(f"connect_function raised ImportError for importable module: {e}")
85
+ finally:
86
+ if real_module is not None:
87
+ sys.modules["intersystems_iris"] = real_module
88
+ elif "intersystems_iris" in sys.modules:
89
+ del sys.modules["intersystems_iris"]
90
+
91
+
92
+ class TestSingletonPoisoning:
93
+ """Fix #1: connect resolved at call time, not detection time."""
94
+
95
+ def test_mock_does_not_poison_after_patch_exits(self):
96
+ """After patch context exits, get_connection must use real connect, not MagicMock."""
97
+ fake = MagicMock()
98
+ with patch.dict(sys.modules, {"intersystems_iris": fake}):
99
+ dc.reset_adapter() # force re-detection while mock is active
100
+ info_inside = dc.get_package_info()
101
+ assert isinstance(info_inside.connect_function, MagicMock)
102
+
103
+ # sys.modules restored — real module back
104
+ dc.reset_adapter()
105
+ try:
106
+ info_after = dc.get_package_info()
107
+ # connect_function must now be the real one, not the MagicMock
108
+ assert not isinstance(info_after.connect_function, MagicMock), (
109
+ "Singleton poisoning: connect_function is still a MagicMock after patch exited"
110
+ )
111
+ except Exception:
112
+ # Package not installed in test env — that's fine, not the bug we're testing
113
+ pass
114
+
115
+ def test_connect_function_is_live_attr_not_bound_at_detection(self):
116
+ """connect_function property must return current module attribute, not cached ref."""
117
+ fake_module = MagicMock()
118
+ real_connect = object() # sentinel
119
+ fake_module.connect = real_connect
120
+
121
+ with patch.dict(sys.modules, {"intersystems_iris": fake_module}):
122
+ dc.reset_adapter()
123
+ info = dc.get_package_info()
124
+ assert info.connect_function is real_connect
125
+
126
+ # Swap the connect on the live module — info.connect_function must follow
127
+ new_connect = object()
128
+ fake_module.connect = new_connect
129
+ assert info.connect_function is new_connect, (
130
+ "connect_function is bound at detection time instead of being resolved live"
131
+ )
132
+
133
+
134
+ class TestResetAdapter:
135
+ """Fix #2: public reset_adapter() lets consumers manage the singleton cleanly."""
136
+
137
+ def test_reset_adapter_clears_singleton(self):
138
+ fake = MagicMock()
139
+ with patch.dict(sys.modules, {"intersystems_iris": fake}):
140
+ dc.reset_adapter()
141
+ _ = dc.get_package_info() # builds singleton with mock
142
+ # Private global should be None after reset
143
+ dc.reset_adapter()
144
+ assert dc._adapter is None
145
+
146
+ def test_reset_adapter_exported(self):
147
+ assert "reset_adapter" in dc.__all__
148
+
149
+ def test_reset_adapter_idempotent(self):
150
+ dc.reset_adapter()
151
+ dc.reset_adapter() # must not raise
152
+ assert dc._adapter is None
153
+
154
+
155
+ class TestDBAPIPackageInfo:
156
+ """connect_function must be a live property, not a stored Callable."""
157
+
158
+ def test_connect_function_property_returns_current_module_attr(self):
159
+ fake = MagicMock()
160
+ sentinel_1 = object()
161
+ sentinel_2 = object()
162
+ fake.connect = sentinel_1
163
+
164
+ with patch.dict(sys.modules, {"intersystems_iris": fake}):
165
+ dc.reset_adapter()
166
+ info = dc.get_package_info()
167
+ assert info.connect_function is sentinel_1
168
+
169
+ fake.connect = sentinel_2
170
+ assert info.connect_function is sentinel_2
171
+
172
+ def test_package_info_still_has_package_name_and_version(self):
173
+ fake = MagicMock()
174
+ fake.connect = MagicMock()
175
+
176
+ with patch.dict(sys.modules, {"intersystems_iris": fake}), patch(
177
+ "importlib.metadata.version", return_value="5.2.0"
178
+ ):
179
+ dc.reset_adapter()
180
+ info = dc.get_package_info()
181
+ assert info.package_name == "intersystems-irispython"
182
+ assert info.version == "5.2.0"
183
+ assert info.import_path == "intersystems_iris"
File without changes