iris-devtester 1.9.3__tar.gz → 1.10.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.
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/PKG-INFO +42 -3
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/README.md +41 -2
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/SKILL.md +1 -1
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/__init__.py +1 -1
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/container.py +184 -10
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/container_config.py +10 -4
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/iris_container.py +88 -6
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/PKG-INFO +42 -3
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/pyproject.toml +1 -1
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/config/test_container_config.py +13 -2
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_iris_container.py +47 -3
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/utils/test_iris_container_adapter.py +1 -1
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/AGENTS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/CLAUDE.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/CONSTITUTION.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/LICENSE +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/MANIFEST.in +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/GETTING_STARTED.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/LANGCHAIN_INTEGRATION_QUICKSTART.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/ROADMAP.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/SQL_VS_OBJECTSCRIPT.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/TROUBLESHOOTING.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/WHATS_NEW_v1.4.0.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/AGENTIC_SANDBOX_ENHANCEMENT_REPORT.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/IMPACT_ANALYSIS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/IRIS_DEVTESTER_POSITIONING_REPORT.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/LANGCHAIN_INTEGRATION_STRATEGY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/LANGCHAIN_INTEGRATION_TEST_RESULTS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/PHASE_2_PLAN.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/RAG_TEMPLATES_ANALYSIS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/README.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/STRATEGIC_ROADMAP_SUMMARY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/archive/feature-009-refactor-plan.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/BUG_REPORT.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/EXTRACTION_SUMMARY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/FEATURE_006_SUMMARY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/PHASE2_RESULTS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/PRE_PUBLISH_REVIEW.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/PROGRESS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/PYPI_READINESS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/SESSION-INTEGRATION-TESTS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/SESSION-SUMMARY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/STATUS-002-PIVOTED.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/STATUS-003-COMPLETE.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/STATUS.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/V1_COMPLETION_PLAN.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/development/V1_RELEASE_SUMMARY.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/WSGI-ASGI-SERVER-SETUP.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/agent-skills.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/dat-fixtures.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/docker-compose.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/performance-monitoring.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/features/testcontainers.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/api-contract-synchronization.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/callin-service-requirement.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/cpf-merge-and-container-restarts.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dat-fixtures-docker-exec-pattern.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dat-restore-database-isolation-problem.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dbapi-bulk-insert-performance-issue.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dbapi-objectscript-limitation.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dbapi-password-reset-limitation.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/dbapi-private-module-myth.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/docker-hub-image-naming.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/embedded-python-considerations.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/feature-002-pivot-summary.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/integration-test-dbapi-limitation.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-backup-patterns.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-container-performance.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-container-readiness.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-docker-sdk-environment-variables.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-performance-monitoring-landscape.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/iris-security-users-api.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/password-reset-changeflag-fix.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/rag-templates-production-patterns.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/sql-task-manager-operations.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/test-isolation-fix-summary.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/test-isolation-investigation.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/docs/learnings/testcontainers-ryuk-lifecycle.md +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/01_quickstart.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/02_connection_management.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/04_pytest_fixtures.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/05_ci_cd.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/08_auto_discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/09_enterprise.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/10_docker_compose_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/examples/langchain_integration_example.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/__main__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/connection_commands.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/container_commands.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/cli/fixture_commands.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/auto_discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/container_state.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/defaults.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/models.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/presets.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/config/yaml_loader.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/auto_discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/connection.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/dbapi.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/jdbc.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/manager.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/models.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/connections/retry.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/cpf_manager.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/models.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/monitor_utils.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/monitoring.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/performance.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/validation.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/containers/wait_strategies.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/creator.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/loader.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/manifest.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/obj_export.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/fixtures/validator.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/integrations/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/integrations/langchain.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/ports/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/ports/assignment.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/ports/exceptions.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/ports/registry.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/testing/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/testing/fixtures.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/testing/helpers.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/testing/models.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/testing/schema_reset.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/container_port.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/container_status.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/dbapi_compat.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/enable_callin.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/health_checks.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/iris_container_adapter.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/password.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/progress.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester/utils/test_connection.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/SOURCES.txt +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/dependency_links.txt +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/entry_points.txt +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/requires.txt +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/iris_devtester.egg-info/top_level.txt +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/setup.cfg +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/conftest.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_logs_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_remove_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_restart_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_start_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_status_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_stop_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/cli/test_container_up_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_agent_skills.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_cli_container_commands.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_cli_fixture_commands.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_connection_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_container_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_container_integration_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_container_status_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_container_validation_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_enable_callin_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_fixture_creator_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_fixture_loader_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_fixture_validator_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_iriscontainer_attach.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_legacy_package_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_modern_package_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_monitoring_config_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_package_detection.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_port_registry_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_preconfig_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_reset_verification_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_resource_monitoring_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_retry_logic_contract.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_task_manager_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_test_connection_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/contract/test_testing_fixtures_api.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/e2e/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/e2e/test_skill_workflow.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/conftest.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/test_manual_port_override.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/test_multi_project_isolation.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/test_port_exhaustion.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/test_port_persistence.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/ports/test_stale_cleanup.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_bug_fixes.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_bug_fixes_011.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_cli_container_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_connection_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_container_health_monitor.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_container_status_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_container_validation.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_cpf_merge.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_cpf_presets.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_cpf_security.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_custom_user_remediation.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_dat_fixtures_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_enable_callin_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_fixture_export_patterns.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_fixture_performance.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_fixture_refresh.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_iriscontainer_attach_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_monitor_utils_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_monitoring_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_preconfig_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_reset_both_editions.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_reset_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_reset_macos.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_reset_timing.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_password_reset_validation.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_proactive_password_reset.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_real_world_problems.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_reliable_password_reset.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/integration/test_test_connection_integration.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/__init__.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/config/test_config_hierarchy.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/config/test_yaml_loader.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_auto_discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_config_discovery.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_connection_fallback.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_connection_info.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_cpf_manager.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_iris_config.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_manifest.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_monitoring_policy.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_password_preconfig.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_password_preconfig_unit.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_performance_metrics.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_resource_thresholds.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_retry.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_schema_models.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_validation_results.py +0 -0
- {iris_devtester-1.9.3 → iris_devtester-1.10.0}/tests/unit/test_wait_strategies.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris-devtester
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
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>
|
|
@@ -107,9 +107,17 @@ def test_connection():
|
|
|
107
107
|
assert cursor.fetchone()[0] == 1
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
## Container
|
|
110
|
+
## Container Editions
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Three canonical container editions are available:
|
|
113
|
+
|
|
114
|
+
| Edition | Size | Use Case | Image |
|
|
115
|
+
|---------|------|----------|-------|
|
|
116
|
+
| **Community** | ~972MB | Development, testing | `intersystemsdc/iris-community` |
|
|
117
|
+
| **Enterprise** | ~1GB+ | Production testing | `containers.intersystems.com/intersystems/iris` |
|
|
118
|
+
| **Light** | **~580MB** | CI/CD pipelines | `caretdev/iris-community-light` |
|
|
119
|
+
|
|
120
|
+
### Python API
|
|
113
121
|
```python
|
|
114
122
|
from iris_devtester.containers import IRISContainer
|
|
115
123
|
|
|
@@ -117,11 +125,42 @@ from iris_devtester.containers import IRISContainer
|
|
|
117
125
|
with IRISContainer.community() as iris:
|
|
118
126
|
conn = iris.get_connection()
|
|
119
127
|
|
|
128
|
+
# Light Edition (85% smaller, for CI/CD)
|
|
129
|
+
with IRISContainer.light() as iris:
|
|
130
|
+
conn = iris.get_connection()
|
|
131
|
+
|
|
120
132
|
# Enterprise Edition (requires license)
|
|
121
133
|
with IRISContainer.enterprise(license_key="/path/to/iris.key") as iris:
|
|
122
134
|
conn = iris.get_connection()
|
|
135
|
+
|
|
136
|
+
# Specify version
|
|
137
|
+
with IRISContainer.community(version="2025.1") as iris:
|
|
138
|
+
conn = iris.get_connection()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### CLI Usage
|
|
142
|
+
```bash
|
|
143
|
+
# Community (default)
|
|
144
|
+
iris-devtester container up
|
|
145
|
+
|
|
146
|
+
# Light edition for CI/CD
|
|
147
|
+
iris-devtester container up --edition light
|
|
148
|
+
|
|
149
|
+
# Enterprise edition with license
|
|
150
|
+
iris-devtester container up --edition enterprise --license /path/to/iris.key
|
|
151
|
+
|
|
152
|
+
# List running IRIS containers
|
|
153
|
+
iris-devtester container list
|
|
123
154
|
```
|
|
124
155
|
|
|
156
|
+
### Light Edition Details
|
|
157
|
+
|
|
158
|
+
The Light edition removes components unnecessary for SQL-only workloads:
|
|
159
|
+
- **Removed**: Interoperability/Ensemble, Management Portal, DeepSee/BI, CSP/REST
|
|
160
|
+
- **Kept**: SQL engine, DBAPI, JDBC, ODBC, SQLAlchemy-IRIS support
|
|
161
|
+
|
|
162
|
+
Perfect for microservices, automated testing, and Python/SQL pipelines.
|
|
163
|
+
|
|
125
164
|
### Builder Methods
|
|
126
165
|
```python
|
|
127
166
|
# Set a custom container name (for debugging, logs, multiple containers)
|
|
@@ -43,9 +43,17 @@ def test_connection():
|
|
|
43
43
|
assert cursor.fetchone()[0] == 1
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
## Container
|
|
46
|
+
## Container Editions
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Three canonical container editions are available:
|
|
49
|
+
|
|
50
|
+
| Edition | Size | Use Case | Image |
|
|
51
|
+
|---------|------|----------|-------|
|
|
52
|
+
| **Community** | ~972MB | Development, testing | `intersystemsdc/iris-community` |
|
|
53
|
+
| **Enterprise** | ~1GB+ | Production testing | `containers.intersystems.com/intersystems/iris` |
|
|
54
|
+
| **Light** | **~580MB** | CI/CD pipelines | `caretdev/iris-community-light` |
|
|
55
|
+
|
|
56
|
+
### Python API
|
|
49
57
|
```python
|
|
50
58
|
from iris_devtester.containers import IRISContainer
|
|
51
59
|
|
|
@@ -53,11 +61,42 @@ from iris_devtester.containers import IRISContainer
|
|
|
53
61
|
with IRISContainer.community() as iris:
|
|
54
62
|
conn = iris.get_connection()
|
|
55
63
|
|
|
64
|
+
# Light Edition (85% smaller, for CI/CD)
|
|
65
|
+
with IRISContainer.light() as iris:
|
|
66
|
+
conn = iris.get_connection()
|
|
67
|
+
|
|
56
68
|
# Enterprise Edition (requires license)
|
|
57
69
|
with IRISContainer.enterprise(license_key="/path/to/iris.key") as iris:
|
|
58
70
|
conn = iris.get_connection()
|
|
71
|
+
|
|
72
|
+
# Specify version
|
|
73
|
+
with IRISContainer.community(version="2025.1") as iris:
|
|
74
|
+
conn = iris.get_connection()
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### CLI Usage
|
|
78
|
+
```bash
|
|
79
|
+
# Community (default)
|
|
80
|
+
iris-devtester container up
|
|
81
|
+
|
|
82
|
+
# Light edition for CI/CD
|
|
83
|
+
iris-devtester container up --edition light
|
|
84
|
+
|
|
85
|
+
# Enterprise edition with license
|
|
86
|
+
iris-devtester container up --edition enterprise --license /path/to/iris.key
|
|
87
|
+
|
|
88
|
+
# List running IRIS containers
|
|
89
|
+
iris-devtester container list
|
|
59
90
|
```
|
|
60
91
|
|
|
92
|
+
### Light Edition Details
|
|
93
|
+
|
|
94
|
+
The Light edition removes components unnecessary for SQL-only workloads:
|
|
95
|
+
- **Removed**: Interoperability/Ensemble, Management Portal, DeepSee/BI, CSP/REST
|
|
96
|
+
- **Kept**: SQL engine, DBAPI, JDBC, ODBC, SQLAlchemy-IRIS support
|
|
97
|
+
|
|
98
|
+
Perfect for microservices, automated testing, and Python/SQL pipelines.
|
|
99
|
+
|
|
61
100
|
### Builder Methods
|
|
62
101
|
```python
|
|
63
102
|
# Set a custom container name (for debugging, logs, multiple containers)
|
|
@@ -3,7 +3,7 @@ name: iris-devtester
|
|
|
3
3
|
description: Battle-tested InterSystems IRIS infrastructure utilities for Python database testing.
|
|
4
4
|
triggers: [iris, database, testing, container, fixture, gof, connection, remediation]
|
|
5
5
|
metadata:
|
|
6
|
-
version: 1.
|
|
6
|
+
version: 1.10.0
|
|
7
7
|
author: InterSystems Community
|
|
8
8
|
principles: [library-first, dbapi-first, isolation-by-default, fail-fast]
|
|
9
9
|
---
|
|
@@ -37,6 +37,19 @@ def container_group(ctx):
|
|
|
37
37
|
default=None,
|
|
38
38
|
help="Container name (default: iris_db)",
|
|
39
39
|
)
|
|
40
|
+
@click.option(
|
|
41
|
+
"--edition",
|
|
42
|
+
type=click.Choice(["community", "enterprise", "light"], case_sensitive=False),
|
|
43
|
+
default="community",
|
|
44
|
+
help="IRIS edition: community (default), enterprise (requires license), light (minimal for CI/CD)",
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--license",
|
|
48
|
+
"license_key",
|
|
49
|
+
type=click.Path(exists=True),
|
|
50
|
+
default=None,
|
|
51
|
+
help="Path to iris.key license file (required for enterprise edition)",
|
|
52
|
+
)
|
|
40
53
|
@click.option(
|
|
41
54
|
"--detach/--no-detach",
|
|
42
55
|
default=True,
|
|
@@ -47,7 +60,7 @@ def container_group(ctx):
|
|
|
47
60
|
)
|
|
48
61
|
@click.option("--cpf", help="Path to CPF merge file or raw CPF content")
|
|
49
62
|
@click.pass_context
|
|
50
|
-
def up(ctx, config, name, detach, timeout, cpf):
|
|
63
|
+
def up(ctx, config, name, edition, license_key, detach, timeout, cpf):
|
|
51
64
|
"""
|
|
52
65
|
Create and start IRIS container from configuration.
|
|
53
66
|
|
|
@@ -64,18 +77,18 @@ def up(ctx, config, name, detach, timeout, cpf):
|
|
|
64
77
|
# Zero-config (uses Community edition defaults)
|
|
65
78
|
iris-devtester container up
|
|
66
79
|
|
|
80
|
+
# Light edition for CI/CD (85% smaller, faster startup)
|
|
81
|
+
iris-devtester container up --edition light
|
|
82
|
+
|
|
83
|
+
# Enterprise edition with license
|
|
84
|
+
iris-devtester container up --edition enterprise --license /path/to/iris.key
|
|
85
|
+
|
|
67
86
|
# With custom container name
|
|
68
87
|
iris-devtester container up --name my-test-db
|
|
69
88
|
|
|
70
89
|
# With custom configuration including volumes
|
|
71
90
|
iris-devtester container up --config iris-config.yml
|
|
72
91
|
|
|
73
|
-
# Example iris-config.yml with volumes:
|
|
74
|
-
# edition: community
|
|
75
|
-
# volumes:
|
|
76
|
-
# - ./workspace:/external/workspace
|
|
77
|
-
# - ./config:/opt/config:ro
|
|
78
|
-
|
|
79
92
|
# Foreground mode (see logs)
|
|
80
93
|
iris-devtester container up --no-detach
|
|
81
94
|
"""
|
|
@@ -99,6 +112,32 @@ def up(ctx, config, name, detach, timeout, cpf):
|
|
|
99
112
|
container_config.container_name = name
|
|
100
113
|
click.echo(f" → Container name: {name}")
|
|
101
114
|
|
|
115
|
+
# Override edition if provided via --edition
|
|
116
|
+
if edition:
|
|
117
|
+
edition_lower = edition.lower()
|
|
118
|
+
container_config.edition = edition_lower
|
|
119
|
+
|
|
120
|
+
# Set appropriate image based on edition
|
|
121
|
+
if edition_lower == "light":
|
|
122
|
+
# Light edition: caretdev/iris-community-light (85% smaller)
|
|
123
|
+
container_config.image_tag = "latest-em"
|
|
124
|
+
click.echo(
|
|
125
|
+
click.style(f" → Edition: light", fg="cyan")
|
|
126
|
+
+ " (minimal for CI/CD, ~580MB vs ~3.5GB)"
|
|
127
|
+
)
|
|
128
|
+
elif edition_lower == "enterprise":
|
|
129
|
+
if not license_key:
|
|
130
|
+
raise click.ClickException(
|
|
131
|
+
"Enterprise edition requires --license option.\n"
|
|
132
|
+
"\n"
|
|
133
|
+
"Usage: iris-devtester container up --edition enterprise --license /path/to/iris.key"
|
|
134
|
+
)
|
|
135
|
+
container_config.license_key = license_key
|
|
136
|
+
click.echo(f" → Edition: enterprise")
|
|
137
|
+
click.echo(f" → License: {license_key}")
|
|
138
|
+
else:
|
|
139
|
+
click.echo(f" → Edition: community")
|
|
140
|
+
|
|
102
141
|
if cpf:
|
|
103
142
|
container_config.cpf_merge = cpf
|
|
104
143
|
click.echo(f" → CPF Merge: {cpf[:50]}...")
|
|
@@ -272,6 +311,141 @@ def up(ctx, config, name, detach, timeout, cpf):
|
|
|
272
311
|
ctx.exit(1)
|
|
273
312
|
|
|
274
313
|
|
|
314
|
+
@container_group.command(name="list")
|
|
315
|
+
@click.option(
|
|
316
|
+
"--all", "-a", "show_all", is_flag=True, help="Show all containers (including stopped)"
|
|
317
|
+
)
|
|
318
|
+
@click.option(
|
|
319
|
+
"--format",
|
|
320
|
+
"output_format",
|
|
321
|
+
type=click.Choice(["table", "json"], case_sensitive=False),
|
|
322
|
+
default="table",
|
|
323
|
+
help="Output format (default: table)",
|
|
324
|
+
)
|
|
325
|
+
@click.pass_context
|
|
326
|
+
def list_containers(ctx, show_all, output_format):
|
|
327
|
+
"""
|
|
328
|
+
List IRIS containers.
|
|
329
|
+
|
|
330
|
+
Shows all IRIS containers managed by iris-devtester, with their status,
|
|
331
|
+
edition, ports, and age.
|
|
332
|
+
|
|
333
|
+
\b
|
|
334
|
+
Examples:
|
|
335
|
+
# List running containers
|
|
336
|
+
iris-devtester container list
|
|
337
|
+
|
|
338
|
+
# List all containers (including stopped)
|
|
339
|
+
iris-devtester container list --all
|
|
340
|
+
|
|
341
|
+
# JSON output for scripting
|
|
342
|
+
iris-devtester container list --format json
|
|
343
|
+
"""
|
|
344
|
+
from datetime import datetime
|
|
345
|
+
|
|
346
|
+
import docker
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
client = docker.from_env()
|
|
350
|
+
|
|
351
|
+
# Find IRIS containers (by image name patterns)
|
|
352
|
+
iris_patterns = [
|
|
353
|
+
"iris-community",
|
|
354
|
+
"intersystems/iris",
|
|
355
|
+
"caretdev/iris",
|
|
356
|
+
"intersystemsdc/iris",
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
containers = client.containers.list(all=show_all)
|
|
360
|
+
iris_containers = []
|
|
361
|
+
|
|
362
|
+
for container in containers:
|
|
363
|
+
image_name = (
|
|
364
|
+
container.image.tags[0] if container.image.tags else str(container.image.id)[:12]
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Check if this is an IRIS container
|
|
368
|
+
is_iris = any(pattern in image_name.lower() for pattern in iris_patterns)
|
|
369
|
+
if not is_iris:
|
|
370
|
+
continue
|
|
371
|
+
|
|
372
|
+
# Determine edition from image name
|
|
373
|
+
if "light" in image_name.lower():
|
|
374
|
+
edition = "light"
|
|
375
|
+
elif "community" in image_name.lower():
|
|
376
|
+
edition = "community"
|
|
377
|
+
else:
|
|
378
|
+
edition = "enterprise"
|
|
379
|
+
|
|
380
|
+
# Get port mappings
|
|
381
|
+
ports = container.attrs.get("NetworkSettings", {}).get("Ports", {})
|
|
382
|
+
port_str = "-"
|
|
383
|
+
if ports and ports.get("1972/tcp"):
|
|
384
|
+
host_port = ports["1972/tcp"][0]["HostPort"]
|
|
385
|
+
port_str = f"{host_port}->1972"
|
|
386
|
+
|
|
387
|
+
# Calculate age
|
|
388
|
+
created = container.attrs.get("Created", "")
|
|
389
|
+
age_str = "unknown"
|
|
390
|
+
if created:
|
|
391
|
+
try:
|
|
392
|
+
# Parse ISO format timestamp
|
|
393
|
+
created_dt = datetime.fromisoformat(created.replace("Z", "+00:00"))
|
|
394
|
+
now = datetime.now(created_dt.tzinfo)
|
|
395
|
+
delta = now - created_dt
|
|
396
|
+
if delta.days > 0:
|
|
397
|
+
age_str = f"{delta.days}d"
|
|
398
|
+
elif delta.seconds > 3600:
|
|
399
|
+
age_str = f"{delta.seconds // 3600}h"
|
|
400
|
+
else:
|
|
401
|
+
age_str = f"{delta.seconds // 60}m"
|
|
402
|
+
except Exception:
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
iris_containers.append(
|
|
406
|
+
{
|
|
407
|
+
"name": container.name,
|
|
408
|
+
"edition": edition,
|
|
409
|
+
"status": container.status,
|
|
410
|
+
"ports": port_str,
|
|
411
|
+
"age": age_str,
|
|
412
|
+
"image": image_name,
|
|
413
|
+
}
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
if output_format == "json":
|
|
417
|
+
import json as json_module
|
|
418
|
+
|
|
419
|
+
click.echo(json_module.dumps(iris_containers, indent=2))
|
|
420
|
+
else:
|
|
421
|
+
# Table format
|
|
422
|
+
if not iris_containers:
|
|
423
|
+
click.echo("No IRIS containers found.")
|
|
424
|
+
if not show_all:
|
|
425
|
+
click.echo("Use --all to include stopped containers.")
|
|
426
|
+
else:
|
|
427
|
+
# Print header
|
|
428
|
+
click.echo(f"{'NAME':<20} {'EDITION':<12} {'STATUS':<10} {'PORTS':<15} {'AGE':<6}")
|
|
429
|
+
click.echo("-" * 65)
|
|
430
|
+
|
|
431
|
+
for c in iris_containers:
|
|
432
|
+
status_color = "green" if c["status"] == "running" else "yellow"
|
|
433
|
+
click.echo(
|
|
434
|
+
f"{c['name']:<20} "
|
|
435
|
+
f"{c['edition']:<12} "
|
|
436
|
+
f"{click.style(c['status'], fg=status_color):<19} "
|
|
437
|
+
f"{c['ports']:<15} "
|
|
438
|
+
f"{c['age']:<6}"
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
except docker.errors.DockerException as e:
|
|
442
|
+
progress.print_error(f"Docker error: {e}")
|
|
443
|
+
ctx.exit(1)
|
|
444
|
+
except Exception as e:
|
|
445
|
+
progress.print_error(f"Error listing containers: {e}")
|
|
446
|
+
ctx.exit(1)
|
|
447
|
+
|
|
448
|
+
|
|
275
449
|
@container_group.command(name="start")
|
|
276
450
|
@click.argument("container_name", required=False, default="iris_db")
|
|
277
451
|
@click.option(
|
|
@@ -657,7 +831,7 @@ def remove(ctx, container_name, force, volumes):
|
|
|
657
831
|
|
|
658
832
|
|
|
659
833
|
@container_group.command(name="reset-password")
|
|
660
|
-
@click.argument("container_name")
|
|
834
|
+
@click.argument("container_name", required=False, default="iris_db")
|
|
661
835
|
@click.option("--user", default="_SYSTEM", help="Username to reset password for (default: _SYSTEM)")
|
|
662
836
|
@click.option("--password", default="SYS", help="New password (default: SYS)")
|
|
663
837
|
@click.option(
|
|
@@ -723,7 +897,7 @@ def reset_password_cmd(ctx, container_name, user, password, port):
|
|
|
723
897
|
|
|
724
898
|
|
|
725
899
|
@container_group.command(name="test-connection")
|
|
726
|
-
@click.argument("container_name")
|
|
900
|
+
@click.argument("container_name", required=False, default="iris_db")
|
|
727
901
|
@click.option(
|
|
728
902
|
"--namespace", default="USER", help="IRIS namespace to test connection to (default: USER)"
|
|
729
903
|
)
|
|
@@ -812,7 +986,7 @@ def test_connection_cmd(ctx, container_name, namespace, username, password):
|
|
|
812
986
|
|
|
813
987
|
|
|
814
988
|
@container_group.command(name="enable-callin")
|
|
815
|
-
@click.argument("container_name")
|
|
989
|
+
@click.argument("container_name", required=False, default="iris_db")
|
|
816
990
|
@click.option(
|
|
817
991
|
"--timeout", type=int, default=30, help="Timeout in seconds for docker commands (default: 30)"
|
|
818
992
|
)
|
|
@@ -51,7 +51,7 @@ class ContainerConfig(BaseModel):
|
|
|
51
51
|
... )
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
-
edition: Literal["community", "enterprise"] = Field(
|
|
54
|
+
edition: Literal["community", "enterprise", "light"] = Field(
|
|
55
55
|
default="community", description="IRIS edition to use"
|
|
56
56
|
)
|
|
57
57
|
container_name: str = Field(
|
|
@@ -245,15 +245,21 @@ class ContainerConfig(BaseModel):
|
|
|
245
245
|
return cls()
|
|
246
246
|
|
|
247
247
|
def get_image_name(self) -> str:
|
|
248
|
+
"""Get the Docker image name based on edition and configuration."""
|
|
248
249
|
if self.image:
|
|
249
250
|
return self.image
|
|
250
251
|
|
|
251
252
|
if self.edition == "community":
|
|
252
|
-
|
|
253
|
-
# Bug Fix #1: Community images use 'intersystemsdc/' prefix on Docker Hub
|
|
253
|
+
# Community images use 'intersystemsdc/' prefix on Docker Hub
|
|
254
254
|
return f"intersystemsdc/iris-community:{self.image_tag}"
|
|
255
|
+
elif self.edition == "light":
|
|
256
|
+
# Light edition: caretdev/iris-community-light (85% smaller)
|
|
257
|
+
# Use latest-em for LTS stability
|
|
258
|
+
tag = self.image_tag if self.image_tag != "latest" else "latest-em"
|
|
259
|
+
return f"caretdev/iris-community-light:{tag}"
|
|
255
260
|
else:
|
|
256
|
-
|
|
261
|
+
# Enterprise edition
|
|
262
|
+
return f"containers.intersystems.com/intersystems/iris:{self.image_tag}"
|
|
257
263
|
|
|
258
264
|
def validate_volume_paths(self) -> List[str]:
|
|
259
265
|
"""
|
|
@@ -94,25 +94,107 @@ class IRISContainer(IRISBase):
|
|
|
94
94
|
self._preconfigure_username: Optional[str] = None
|
|
95
95
|
|
|
96
96
|
@classmethod
|
|
97
|
-
def community(
|
|
98
|
-
|
|
97
|
+
def community(
|
|
98
|
+
cls, image: Optional[str] = None, version: str = "latest", **kwargs
|
|
99
|
+
) -> "IRISContainer":
|
|
100
|
+
"""
|
|
101
|
+
Create a Community Edition container.
|
|
102
|
+
|
|
103
|
+
Auto-detects architecture (ARM64 vs x86) and pulls the appropriate image.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
image: Docker image to use. If None, auto-detects based on architecture.
|
|
107
|
+
version: Image version tag. Options: 'latest', '2025.1', '2025.2', etc.
|
|
108
|
+
"""
|
|
99
109
|
if image is None:
|
|
100
110
|
import platform as platform_module
|
|
101
111
|
|
|
102
112
|
if platform_module.machine() == "arm64":
|
|
103
|
-
|
|
113
|
+
# ARM64 (Apple Silicon) - use official InterSystems registry
|
|
114
|
+
tag = version if version != "latest" else "2025.1"
|
|
115
|
+
image = f"containers.intersystems.com/intersystems/iris-community:{tag}"
|
|
104
116
|
else:
|
|
105
|
-
|
|
117
|
+
# x86_64 - use Docker Hub community image
|
|
118
|
+
image = f"intersystemsdc/iris-community:{version}"
|
|
106
119
|
return cls(image=image, **kwargs)
|
|
107
120
|
|
|
108
121
|
@classmethod
|
|
109
|
-
def enterprise(
|
|
110
|
-
|
|
122
|
+
def enterprise(
|
|
123
|
+
cls, license_key: Optional[str] = None, image: Optional[str] = None, **kwargs
|
|
124
|
+
) -> "IRISContainer":
|
|
125
|
+
"""
|
|
126
|
+
Create an Enterprise Edition container.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
license_key: Path to iris.key file. If None, checks IRIS_LICENSE_KEY env var.
|
|
130
|
+
image: Docker image to use. Defaults to containers.intersystems.com/intersystems/iris:latest
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If no license key is provided or found in environment.
|
|
134
|
+
"""
|
|
135
|
+
import os
|
|
136
|
+
|
|
137
|
+
if license_key is None:
|
|
138
|
+
license_key = os.environ.get("IRIS_LICENSE_KEY")
|
|
139
|
+
|
|
140
|
+
if license_key is None:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
"Enterprise edition requires a license key.\n"
|
|
143
|
+
"\n"
|
|
144
|
+
"Provide license_key parameter or set IRIS_LICENSE_KEY environment variable:\n"
|
|
145
|
+
" IRISContainer.enterprise(license_key='/path/to/iris.key')\n"
|
|
146
|
+
" # or\n"
|
|
147
|
+
" export IRIS_LICENSE_KEY=/path/to/iris.key"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if not os.path.exists(license_key):
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"License key file not found: {license_key}\n"
|
|
153
|
+
"\n"
|
|
154
|
+
"Verify the license key path exists and is readable."
|
|
155
|
+
)
|
|
156
|
+
|
|
111
157
|
if image is None:
|
|
112
158
|
image = "containers.intersystems.com/intersystems/iris:latest"
|
|
159
|
+
|
|
113
160
|
container = cls(image=image, **kwargs)
|
|
161
|
+
# Mount license key into container
|
|
162
|
+
container._license_key_path = license_key
|
|
114
163
|
return container
|
|
115
164
|
|
|
165
|
+
@classmethod
|
|
166
|
+
def light(
|
|
167
|
+
cls, image: Optional[str] = None, version: str = "latest", **kwargs
|
|
168
|
+
) -> "IRISContainer":
|
|
169
|
+
"""
|
|
170
|
+
Create a Light Edition container optimized for CI/CD.
|
|
171
|
+
|
|
172
|
+
Light edition is ~85% smaller than full Community edition (~580MB vs ~3.5GB).
|
|
173
|
+
It removes Interoperability, Management Portal, DeepSee, and web components.
|
|
174
|
+
DBAPI, JDBC, and ODBC connectivity are fully supported.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
image: Docker image to use. Defaults to caretdev/iris-community-light.
|
|
178
|
+
version: Image version tag. Options: 'latest', 'latest-em' (LTS), '2025.1', etc.
|
|
179
|
+
|
|
180
|
+
Best for:
|
|
181
|
+
- CI/CD pipelines
|
|
182
|
+
- Microservices
|
|
183
|
+
- Automated testing
|
|
184
|
+
- SQL-only workloads
|
|
185
|
+
|
|
186
|
+
Not supported:
|
|
187
|
+
- Interoperability/Ensemble
|
|
188
|
+
- Management Portal
|
|
189
|
+
- DeepSee/BI
|
|
190
|
+
- CSP/REST web framework
|
|
191
|
+
"""
|
|
192
|
+
if image is None:
|
|
193
|
+
# Use latest-em for LTS stability, or allow version override
|
|
194
|
+
tag = version if version != "latest" else "latest-em"
|
|
195
|
+
image = f"caretdev/iris-community-light:{tag}"
|
|
196
|
+
return cls(image=image, **kwargs)
|
|
197
|
+
|
|
116
198
|
def with_name(self, name: str) -> "IRISContainer":
|
|
117
199
|
"""Set the container name."""
|
|
118
200
|
self._container_name = name
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris-devtester
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
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>
|
|
@@ -107,9 +107,17 @@ def test_connection():
|
|
|
107
107
|
assert cursor.fetchone()[0] == 1
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
## Container
|
|
110
|
+
## Container Editions
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Three canonical container editions are available:
|
|
113
|
+
|
|
114
|
+
| Edition | Size | Use Case | Image |
|
|
115
|
+
|---------|------|----------|-------|
|
|
116
|
+
| **Community** | ~972MB | Development, testing | `intersystemsdc/iris-community` |
|
|
117
|
+
| **Enterprise** | ~1GB+ | Production testing | `containers.intersystems.com/intersystems/iris` |
|
|
118
|
+
| **Light** | **~580MB** | CI/CD pipelines | `caretdev/iris-community-light` |
|
|
119
|
+
|
|
120
|
+
### Python API
|
|
113
121
|
```python
|
|
114
122
|
from iris_devtester.containers import IRISContainer
|
|
115
123
|
|
|
@@ -117,11 +125,42 @@ from iris_devtester.containers import IRISContainer
|
|
|
117
125
|
with IRISContainer.community() as iris:
|
|
118
126
|
conn = iris.get_connection()
|
|
119
127
|
|
|
128
|
+
# Light Edition (85% smaller, for CI/CD)
|
|
129
|
+
with IRISContainer.light() as iris:
|
|
130
|
+
conn = iris.get_connection()
|
|
131
|
+
|
|
120
132
|
# Enterprise Edition (requires license)
|
|
121
133
|
with IRISContainer.enterprise(license_key="/path/to/iris.key") as iris:
|
|
122
134
|
conn = iris.get_connection()
|
|
135
|
+
|
|
136
|
+
# Specify version
|
|
137
|
+
with IRISContainer.community(version="2025.1") as iris:
|
|
138
|
+
conn = iris.get_connection()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### CLI Usage
|
|
142
|
+
```bash
|
|
143
|
+
# Community (default)
|
|
144
|
+
iris-devtester container up
|
|
145
|
+
|
|
146
|
+
# Light edition for CI/CD
|
|
147
|
+
iris-devtester container up --edition light
|
|
148
|
+
|
|
149
|
+
# Enterprise edition with license
|
|
150
|
+
iris-devtester container up --edition enterprise --license /path/to/iris.key
|
|
151
|
+
|
|
152
|
+
# List running IRIS containers
|
|
153
|
+
iris-devtester container list
|
|
123
154
|
```
|
|
124
155
|
|
|
156
|
+
### Light Edition Details
|
|
157
|
+
|
|
158
|
+
The Light edition removes components unnecessary for SQL-only workloads:
|
|
159
|
+
- **Removed**: Interoperability/Ensemble, Management Portal, DeepSee/BI, CSP/REST
|
|
160
|
+
- **Kept**: SQL engine, DBAPI, JDBC, ODBC, SQLAlchemy-IRIS support
|
|
161
|
+
|
|
162
|
+
Perfect for microservices, automated testing, and Python/SQL pipelines.
|
|
163
|
+
|
|
125
164
|
### Builder Methods
|
|
126
165
|
```python
|
|
127
166
|
# Set a custom container name (for debugging, logs, multiple containers)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iris-devtester"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.10.0"
|
|
8
8
|
description = "Battle-tested InterSystems IRIS infrastructure utilities for Python development"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -379,12 +379,23 @@ class TestContainerConfigImageName:
|
|
|
379
379
|
def test_get_image_name_enterprise_latest(self):
|
|
380
380
|
"""Test image name for enterprise edition with latest tag."""
|
|
381
381
|
config = ContainerConfig(edition="enterprise", license_key="TEST-KEY", image_tag="latest")
|
|
382
|
-
assert config.get_image_name() == "intersystems/iris:latest"
|
|
382
|
+
assert config.get_image_name() == "containers.intersystems.com/intersystems/iris:latest"
|
|
383
383
|
|
|
384
384
|
def test_get_image_name_enterprise_specific_tag(self):
|
|
385
385
|
"""Test image name for enterprise edition with specific tag."""
|
|
386
386
|
config = ContainerConfig(edition="enterprise", license_key="TEST-KEY", image_tag="2024.1")
|
|
387
|
-
assert config.get_image_name() == "intersystems/iris:2024.1"
|
|
387
|
+
assert config.get_image_name() == "containers.intersystems.com/intersystems/iris:2024.1"
|
|
388
|
+
|
|
389
|
+
def test_get_image_name_light_latest(self):
|
|
390
|
+
"""Test image name for light edition with latest tag."""
|
|
391
|
+
config = ContainerConfig(edition="light", image_tag="latest")
|
|
392
|
+
# Light uses latest-em for LTS stability
|
|
393
|
+
assert config.get_image_name() == "caretdev/iris-community-light:latest-em"
|
|
394
|
+
|
|
395
|
+
def test_get_image_name_light_specific_tag(self):
|
|
396
|
+
"""Test image name for light edition with specific tag."""
|
|
397
|
+
config = ContainerConfig(edition="light", image_tag="2025.1")
|
|
398
|
+
assert config.get_image_name() == "caretdev/iris-community-light:2025.1"
|
|
388
399
|
|
|
389
400
|
|
|
390
401
|
class TestContainerConfigVolumeValidation:
|