nlp2sql 0.2.0rc15__tar.gz → 0.2.0rc16__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 (174) hide show
  1. nlp2sql-0.2.0rc16/.github/scripts/verify_release_tag.py +48 -0
  2. nlp2sql-0.2.0rc16/.github/workflows/ci.yml +136 -0
  3. nlp2sql-0.2.0rc16/.github/workflows/publish-pypi.yml +115 -0
  4. nlp2sql-0.2.0rc16/.github/workflows/publish-testpypi.yml +90 -0
  5. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/CHANGELOG.md +43 -0
  6. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/CONTRIBUTING.md +16 -0
  7. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/PKG-INFO +2 -1
  8. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/mcp_server/__init__.py +1 -1
  9. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/mcp_server/pyproject.toml +2 -2
  10. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/pyproject.toml +2 -1
  11. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/__init__.py +3 -2
  12. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/cli.py +9 -21
  13. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/client.py +50 -20
  14. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/config/settings.py +1 -1
  15. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/sql_safety.py +29 -4
  16. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/query_service.py +16 -1
  17. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/semantic_validation_service.py +24 -10
  18. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/conftest.py +20 -0
  19. nlp2sql-0.2.0rc16/tests/data/gold_questions.json +58 -0
  20. nlp2sql-0.2.0rc16/tests/fakes/__init__.py +1 -0
  21. nlp2sql-0.2.0rc16/tests/fakes/fake_openai.py +132 -0
  22. nlp2sql-0.2.0rc16/tests/test_cli_setup.py +35 -0
  23. nlp2sql-0.2.0rc16/tests/test_connect_embeddings.py +120 -0
  24. nlp2sql-0.2.0rc16/tests/test_false_invalid_regression.py +36 -0
  25. nlp2sql-0.2.0rc16/tests/test_first_run.py +56 -0
  26. nlp2sql-0.2.0rc16/tests/test_query_service_contract.py +87 -0
  27. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_retrieval_pipeline.py +55 -0
  28. nlp2sql-0.2.0rc16/tests/test_sql_safety.py +40 -0
  29. nlp2sql-0.2.0rc16/tests/test_version_consistency.py +60 -0
  30. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/uv.lock +3 -1
  31. nlp2sql-0.2.0rc15/.github/workflows/ci.yml +0 -84
  32. nlp2sql-0.2.0rc15/.github/workflows/publish-pypi.yml +0 -88
  33. nlp2sql-0.2.0rc15/.github/workflows/publish-testpypi.yml +0 -72
  34. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/commands/db.md +0 -0
  35. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/commands/quality.md +0 -0
  36. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/commands/test.md +0 -0
  37. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/rules/adapters.md +0 -0
  38. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/rules/architecture.md +0 -0
  39. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/rules/python-style.md +0 -0
  40. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/rules/testing.md +0 -0
  41. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.claude/settings.json +0 -0
  42. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  43. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  44. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.gitignore +0 -0
  45. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.mcp.json.example +0 -0
  46. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/.python-version +0 -0
  47. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/CLAUDE.md +0 -0
  48. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/LICENSE +0 -0
  49. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/README.md +0 -0
  50. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/SECURITY.md +0 -0
  51. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/assets/nlp2sql-logo.png +0 -0
  52. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/benchmarks/enterprise_benchmark_results.json +0 -0
  53. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/.env.example +0 -0
  54. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/README.md +0 -0
  55. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/docker-compose.yml +0 -0
  56. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/get-db-urls.sh +0 -0
  57. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/init-schema.sql +0 -0
  58. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/large-schema.sql +0 -0
  59. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/localstack-init.sh +0 -0
  60. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docker/test-redshift.sh +0 -0
  61. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docs/API.md +0 -0
  62. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docs/ARCHITECTURE.md +0 -0
  63. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docs/CONFIGURATION.md +0 -0
  64. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docs/ENTERPRISE.md +0 -0
  65. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/docs/Redshift.md +0 -0
  66. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/README.md +0 -0
  67. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/advanced/test_multiple_providers.py +0 -0
  68. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/advanced/test_simple_api.py +0 -0
  69. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/database_specific/test_odoo_integration.py +0 -0
  70. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/default_examples.json +0 -0
  71. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/documentation/real_world_example.py +0 -0
  72. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/getting_started/basic_usage.py +0 -0
  73. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/getting_started/simple_demo.py +0 -0
  74. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/getting_started/test_api_setup.py +0 -0
  75. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/schema_management/test_auto_schema.py +0 -0
  76. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/schema_management/test_schema_filters_comprehensive.py +0 -0
  77. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/.dockerignore +0 -0
  78. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/.env.example +0 -0
  79. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/DOCKER_README.md +0 -0
  80. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/DOCKER_SETUP.md +0 -0
  81. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/DOCKER_TESTING_SUMMARY.md +0 -0
  82. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/Dockerfile +0 -0
  83. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/INDEX.md +0 -0
  84. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/README.md +0 -0
  85. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/docker/init-ecommerce-schema.sql +0 -0
  86. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/docker-compose.yml +0 -0
  87. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/main.py +0 -0
  88. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/pyproject.toml +0 -0
  89. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/examples/strands-fastapi-agent/test-docker-endpoints.sh +0 -0
  90. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/install-dev.sh +0 -0
  91. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/mcp_server/README.md +0 -0
  92. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/mcp_server/example_config.json +0 -0
  93. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/mcp_server/server.py +0 -0
  94. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/__init__.py +0 -0
  95. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/anthropic_adapter.py +0 -0
  96. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/default_error_classifier.py +0 -0
  97. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/default_repair_policy.py +0 -0
  98. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/dict_semantic_resolver.py +0 -0
  99. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/file_semantic_resolver.py +0 -0
  100. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/gemini_adapter.py +0 -0
  101. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/local_embedding_adapter.py +0 -0
  102. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/noop_semantic_resolver.py +0 -0
  103. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/noop_semantic_validator.py +0 -0
  104. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/openai_adapter.py +0 -0
  105. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/openai_embedding_adapter.py +0 -0
  106. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/pgvector_example_repository.py +0 -0
  107. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/postgres_repository.py +0 -0
  108. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/redshift_adapter.py +0 -0
  109. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/regex_query_validator.py +0 -0
  110. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/adapters/schema_repository_execution_adapter.py +0 -0
  111. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/config/__init__.py +0 -0
  112. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/__init__.py +0 -0
  113. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/database_prompts.py +0 -0
  114. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/entities.py +0 -0
  115. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/provider_config.py +0 -0
  116. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/result.py +0 -0
  117. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/runtime.py +0 -0
  118. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/core/sql_keywords.py +0 -0
  119. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/exceptions/__init__.py +0 -0
  120. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/factories/__init__.py +0 -0
  121. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/factories/repository_factory.py +0 -0
  122. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/__init__.py +0 -0
  123. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/ai_provider.py +0 -0
  124. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/cache.py +0 -0
  125. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/embedding_provider.py +0 -0
  126. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/error_classifier.py +0 -0
  127. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/example_repository.py +0 -0
  128. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/query_execution.py +0 -0
  129. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/query_optimizer.py +0 -0
  130. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/query_safety.py +0 -0
  131. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/query_validator.py +0 -0
  132. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/repair_policy.py +0 -0
  133. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/schema_repository.py +0 -0
  134. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/schema_strategy.py +0 -0
  135. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/semantic_resolver.py +0 -0
  136. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/ports/semantic_validator.py +0 -0
  137. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/__init__.py +0 -0
  138. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/analyzer.py +0 -0
  139. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/embedding_manager.py +0 -0
  140. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/example_loader.py +0 -0
  141. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/example_store.py +0 -0
  142. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/schema/manager.py +0 -0
  143. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/__init__.py +0 -0
  144. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/example_selection_service.py +0 -0
  145. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/prompt_assembly_service.py +0 -0
  146. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/query_analysis_service.py +0 -0
  147. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/query_repair_service.py +0 -0
  148. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/semantic_resolution_service.py +0 -0
  149. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/services/sql_intent_planning_service.py +0 -0
  150. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/utils/__init__.py +0 -0
  151. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/utils/artifact_loader.py +0 -0
  152. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/utils/helpers.py +0 -0
  153. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/utils/semantic_prompt.py +0 -0
  154. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/src/nlp2sql/utils/storage.py +0 -0
  155. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/test_tmp/.gitignore +0 -0
  156. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/mcp/__init__.py +0 -0
  157. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/mcp/test_sql_security.py +0 -0
  158. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_artifact_loader.py +0 -0
  159. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_basic.py +0 -0
  160. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_batch_scoring.py +0 -0
  161. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_cli_semantic_support.py +0 -0
  162. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_client_hooks.py +0 -0
  163. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_column_validation.py +0 -0
  164. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_database_prompts.py +0 -0
  165. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_dsl_integration.py +0 -0
  166. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_embedding_manager.py +0 -0
  167. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_integration.py +0 -0
  168. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_model_defaults.py +0 -0
  169. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_pgvector_example_repository.py +0 -0
  170. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_postgres_integration.py +0 -0
  171. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_provider_compat_llm.py +0 -0
  172. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_redshift_integration.py +0 -0
  173. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_repository_cache.py +0 -0
  174. {nlp2sql-0.2.0rc15 → nlp2sql-0.2.0rc16}/tests/test_repository_factory.py +0 -0
@@ -0,0 +1,48 @@
1
+ """Check that a release tag matches the package version before publishing.
2
+
3
+ The publish workflows run this before building, so a package is only ever
4
+ published from a tag named ``v`` + the ``[project].version`` of pyproject.toml.
5
+
6
+ Usage: python .github/scripts/verify_release_tag.py v0.2.0rc16
7
+ """
8
+
9
+ import argparse
10
+ import re
11
+ import sys
12
+ from pathlib import Path
13
+ from typing import Optional
14
+
15
+ import tomllib
16
+
17
+ TAG_PATTERN = re.compile(r"v\d+\.\d+\.\d+(?:(?:a|b|rc)\d+)?")
18
+ PYPROJECT = Path(__file__).resolve().parents[2] / "pyproject.toml"
19
+ SEE_DOCS = "See 'Releasing (maintainers)' in CONTRIBUTING.md."
20
+
21
+
22
+ def fail(message: str) -> int:
23
+ print(f"::error title=Release tag check failed::{message} {SEE_DOCS}")
24
+ return 1
25
+
26
+
27
+ def main(argv: Optional[list[str]] = None) -> int:
28
+ parser = argparse.ArgumentParser(description="Check that a release tag matches the version in pyproject.toml.")
29
+ parser.add_argument("tag", help="release tag, for example v0.2.0rc16")
30
+ tag = parser.parse_args(argv).tag
31
+
32
+ if not TAG_PATTERN.fullmatch(tag):
33
+ return fail(f"'{tag}' is not a release tag: expected vX.Y.Z, optionally followed by aN, bN or rcN.")
34
+
35
+ with PYPROJECT.open("rb") as file:
36
+ version = tomllib.load(file)["project"]["version"]
37
+ if tag != f"v{version}":
38
+ return fail(
39
+ f"Tag {tag} does not match the pyproject.toml version ({version}) of the checked-out commit. "
40
+ "Was the release created before the version bump was pushed?"
41
+ )
42
+
43
+ print(f"Tag {tag} matches the pyproject.toml version {version}.")
44
+ return 0
45
+
46
+
47
+ if __name__ == "__main__":
48
+ sys.exit(main())
@@ -0,0 +1,136 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main, develop]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-24.04
15
+
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v7
19
+
20
+ - name: Set up Python 3.12
21
+ uses: actions/setup-python@v7
22
+ with:
23
+ python-version: '3.12'
24
+
25
+ - name: Install uv
26
+ run: python -m pip install uv
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ uv pip install --system .
31
+ uv pip install --system ".[dev]"
32
+
33
+ - name: Unit tests
34
+ env:
35
+ PYTHONPATH: src
36
+ run: pytest -m "not integration and not llm" -q
37
+
38
+ pgvector-integration:
39
+ runs-on: ubuntu-24.04
40
+
41
+ services:
42
+ postgres:
43
+ image: pgvector/pgvector:pg16
44
+ env:
45
+ POSTGRES_USER: testuser
46
+ POSTGRES_PASSWORD: testpass
47
+ POSTGRES_DB: testdb
48
+ ports:
49
+ - 5432:5432
50
+ options: >-
51
+ --health-cmd "pg_isready -U testuser -d testdb"
52
+ --health-interval 10s
53
+ --health-timeout 5s
54
+ --health-retries 5
55
+
56
+ steps:
57
+ - name: Checkout
58
+ uses: actions/checkout@v7
59
+
60
+ - name: Set up Python 3.12
61
+ uses: actions/setup-python@v7
62
+ with:
63
+ python-version: '3.12'
64
+
65
+ - name: Install uv
66
+ run: python -m pip install uv
67
+
68
+ - name: Install dependencies (with pgvector extra)
69
+ run: |
70
+ uv pip install --system ".[dev]"
71
+ uv pip install --system ".[pgvector]"
72
+
73
+ - name: Load the e-commerce test schema
74
+ env:
75
+ PGPASSWORD: testpass
76
+ run: psql -h localhost -U testuser -d testdb -v ON_ERROR_STOP=1 -q -f docker/init-schema.sql
77
+
78
+ # Scoped suites so the job stays self-contained (the broader integration
79
+ # suite also needs LocalStack Redshift, out of scope here).
80
+ # NLP2SQL_REQUIRE_INTEGRATION makes the fixtures FAIL instead of skip, so a
81
+ # misconfigured service goes red rather than green-via-skip.
82
+ - name: pgvector integration tests
83
+ env:
84
+ PYTHONPATH: src
85
+ NLP2SQL_REQUIRE_INTEGRATION: "1"
86
+ NLP2SQL_TEST_POSTGRES_HOST: localhost
87
+ NLP2SQL_TEST_POSTGRES_PORT: "5432"
88
+ NLP2SQL_TEST_POSTGRES_USER: testuser
89
+ NLP2SQL_TEST_POSTGRES_PASS: testpass
90
+ NLP2SQL_TEST_POSTGRES_DB: testdb
91
+ run: pytest tests/test_pgvector_example_repository.py -m integration -q
92
+
93
+ # README Quick Start per provider and the false-invalid gold set, with the
94
+ # OpenAI SDK pointed at tests/fakes/fake_openai.py (no keys, no cost).
95
+ - name: First-run regression tests
96
+ env:
97
+ PYTHONPATH: src
98
+ NLP2SQL_REQUIRE_INTEGRATION: "1"
99
+ NLP2SQL_TEST_POSTGRES_HOST: localhost
100
+ NLP2SQL_TEST_POSTGRES_PORT: "5432"
101
+ NLP2SQL_TEST_POSTGRES_USER: testuser
102
+ NLP2SQL_TEST_POSTGRES_PASS: testpass
103
+ NLP2SQL_TEST_POSTGRES_DB: testdb
104
+ run: pytest tests/test_first_run.py tests/test_false_invalid_regression.py -m integration -q
105
+
106
+ # Installs the built wheel the way a user does: fresh environment, no lock
107
+ # file, latest dependency versions. Catches undeclared dependencies (rc13-rc15
108
+ # could not be imported without pyyaml) that the locked dev environment hides.
109
+ clean-install:
110
+ runs-on: ubuntu-24.04
111
+
112
+ steps:
113
+ - name: Checkout
114
+ uses: actions/checkout@v7
115
+
116
+ - name: Set up Python 3.12
117
+ uses: actions/setup-python@v7
118
+ with:
119
+ python-version: '3.12'
120
+
121
+ - name: Build the wheel
122
+ run: |
123
+ python -m pip install build
124
+ python -m build --wheel
125
+
126
+ - name: Install the wheel in a fresh environment
127
+ run: |
128
+ python -m venv "$RUNNER_TEMP/clean"
129
+ "$RUNNER_TEMP/clean/bin/pip" install dist/*.whl
130
+ "$RUNNER_TEMP/clean/bin/pip" list | grep -iE "^(openai|anthropic|google-generativeai|pyyaml) "
131
+
132
+ - name: Import the package and run the CLI
133
+ working-directory: ${{ runner.temp }}
134
+ run: |
135
+ "$RUNNER_TEMP/clean/bin/python" -c "import nlp2sql; print('nlp2sql', nlp2sql.__version__)"
136
+ "$RUNNER_TEMP/clean/bin/nlp2sql" --help
@@ -0,0 +1,115 @@
1
+ name: Publish Python Package to PyPI
2
+
3
+ # Production releases are decided by a tag: run this workflow from the release
4
+ # tag (Run workflow -> Use workflow from -> Tags -> vX.Y.Z). A run from a branch
5
+ # fails before anything is checked out. See "Releasing (maintainers)" in
6
+ # CONTRIBUTING.md.
7
+
8
+ on:
9
+ workflow_dispatch:
10
+ inputs:
11
+ confirm_production:
12
+ description: 'Type "PRODUCTION" to confirm publishing to live PyPI'
13
+ required: true
14
+ default: ''
15
+
16
+ permissions: {}
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-24.04
21
+ permissions:
22
+ contents: read
23
+
24
+ steps:
25
+ - name: Require a tag ref
26
+ run: |
27
+ if [ "$GITHUB_REF_TYPE" != "tag" ]; then
28
+ echo "::error title=Not a tag::Run this workflow from a release tag (Use workflow from -> Tags), not from '$GITHUB_REF_NAME'."
29
+ exit 1
30
+ fi
31
+
32
+ - name: Validate production confirmation
33
+ env:
34
+ CONFIRM_PRODUCTION: ${{ inputs.confirm_production }}
35
+ run: |
36
+ if [ "$CONFIRM_PRODUCTION" != "PRODUCTION" ]; then
37
+ echo "::error::Production confirmation required. Type PRODUCTION to confirm."
38
+ exit 1
39
+ fi
40
+
41
+ - name: Require a published GitHub Release for the tag
42
+ env:
43
+ GH_TOKEN: ${{ github.token }}
44
+ run: |
45
+ is_draft=$(gh release view "$GITHUB_REF_NAME" -R "$GITHUB_REPOSITORY" --json isDraft -q .isDraft) || {
46
+ echo "::error::No GitHub Release found for $GITHUB_REF_NAME. Create and publish the release first."
47
+ exit 1
48
+ }
49
+ if [ "$is_draft" != "false" ]; then
50
+ echo "::error::The GitHub Release for $GITHUB_REF_NAME is still a draft."
51
+ exit 1
52
+ fi
53
+
54
+ - name: Checkout the tag
55
+ uses: actions/checkout@v7
56
+ with:
57
+ persist-credentials: false
58
+
59
+ - name: Set up Python 3.12
60
+ uses: actions/setup-python@v7
61
+ with:
62
+ python-version: '3.12'
63
+
64
+ - name: Verify the tag matches the package version
65
+ run: |
66
+ echo "Tag: $GITHUB_REF_NAME, commit: $GITHUB_SHA"
67
+ python .github/scripts/verify_release_tag.py "$GITHUB_REF_NAME"
68
+
69
+ - name: Install uv
70
+ run: python -m pip install uv
71
+
72
+ - name: Install project dependencies with uv
73
+ run: |
74
+ uv pip install --system .
75
+ uv pip install --system ".[dev]"
76
+
77
+ - name: Install build
78
+ run: python -m pip install build
79
+
80
+ - name: Run tests
81
+ env:
82
+ PYTHONPATH: src
83
+ run: pytest
84
+
85
+ - name: Build package
86
+ run: python -m build
87
+
88
+ - name: Upload distributions
89
+ uses: actions/upload-artifact@v7
90
+ with:
91
+ name: dist
92
+ path: dist/
93
+ if-no-files-found: error
94
+
95
+ publish:
96
+ needs: build
97
+ runs-on: ubuntu-24.04
98
+ environment: pypi
99
+
100
+ # Only this job can request a PyPI token (Trusted Publishing via OIDC), and
101
+ # it runs no project or third-party Python code.
102
+ permissions:
103
+ id-token: write
104
+
105
+ steps:
106
+ - name: Download distributions
107
+ uses: actions/download-artifact@v8
108
+ with:
109
+ name: dist
110
+ path: dist/
111
+
112
+ - name: Publish to PyPI
113
+ uses: pypa/gh-action-pypi-publish@release/v1
114
+ with:
115
+ repository-url: https://upload.pypi.org/legacy/
@@ -0,0 +1,90 @@
1
+ name: Publish Python Package to Test PyPI
2
+
3
+ # Runs automatically on the release tag when a GitHub Release is published, and
4
+ # can be re-run manually from a tag (Use workflow from -> Tags -> vX.Y.Z). A run
5
+ # from a branch fails before anything is checked out. See "Releasing
6
+ # (maintainers)" in CONTRIBUTING.md.
7
+
8
+ on:
9
+ release:
10
+ types: [published]
11
+ workflow_dispatch:
12
+
13
+ permissions: {}
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-24.04
18
+ permissions:
19
+ contents: read
20
+
21
+ steps:
22
+ - name: Require a tag ref
23
+ run: |
24
+ if [ "$GITHUB_REF_TYPE" != "tag" ]; then
25
+ echo "::error title=Not a tag::Run this workflow from a release tag (Use workflow from -> Tags), not from '$GITHUB_REF_NAME'."
26
+ exit 1
27
+ fi
28
+
29
+ - name: Checkout the tag
30
+ uses: actions/checkout@v7
31
+ with:
32
+ persist-credentials: false
33
+
34
+ - name: Set up Python 3.12
35
+ uses: actions/setup-python@v7
36
+ with:
37
+ python-version: '3.12'
38
+
39
+ - name: Verify the tag matches the package version
40
+ run: |
41
+ echo "Tag: $GITHUB_REF_NAME, commit: $GITHUB_SHA"
42
+ python .github/scripts/verify_release_tag.py "$GITHUB_REF_NAME"
43
+
44
+ - name: Install uv
45
+ run: python -m pip install uv
46
+
47
+ - name: Install project dependencies with uv
48
+ run: |
49
+ uv pip install --system .
50
+ uv pip install --system ".[dev]"
51
+
52
+ - name: Install build
53
+ run: python -m pip install build
54
+
55
+ - name: Run tests
56
+ env:
57
+ PYTHONPATH: src
58
+ run: pytest
59
+
60
+ - name: Build package
61
+ run: python -m build
62
+
63
+ - name: Upload distributions
64
+ uses: actions/upload-artifact@v7
65
+ with:
66
+ name: dist
67
+ path: dist/
68
+ if-no-files-found: error
69
+
70
+ publish:
71
+ needs: build
72
+ runs-on: ubuntu-24.04
73
+ environment: testpypi
74
+
75
+ # Only this job can request a Test PyPI token (Trusted Publishing via OIDC),
76
+ # and it runs no project or third-party Python code.
77
+ permissions:
78
+ id-token: write
79
+
80
+ steps:
81
+ - name: Download distributions
82
+ uses: actions/download-artifact@v8
83
+ with:
84
+ name: dist
85
+ path: dist/
86
+
87
+ - name: Publish to Test PyPI
88
+ uses: pypa/gh-action-pypi-publish@release/v1
89
+ with:
90
+ repository-url: https://test.pypi.org/legacy/
@@ -22,6 +22,49 @@ pre-1.0.
22
22
 
23
23
  ## [Unreleased]
24
24
 
25
+ ## [0.2.0rc16] - 2026-10-19
26
+
27
+ ### Changed
28
+ - Release: packages are published to PyPI only from a release tag whose name
29
+ matches the `pyproject.toml` version and that has a published GitHub Release.
30
+ The publish workflows build in one job and upload from another, so only the
31
+ upload job can request a PyPI token.
32
+ - CI: runs on `ubuntu-24.04` with the Node 24 versions of `actions/checkout` and
33
+ `actions/setup-python`, and fails when any copy of the package version is out
34
+ of sync with `pyproject.toml`.
35
+ - CI: a `clean-install` job installs the built wheel in a fresh environment
36
+ without the lock file, and the integration lane runs the README Quick Start
37
+ and a false-invalid regression set against a local fake of the OpenAI API.
38
+
39
+ ### Fixed
40
+ - `import nlp2sql` failed on a plain `pip install nlp2sql` since 0.2.0rc13
41
+ (`No module named 'yaml'`): `pyyaml` is now a declared dependency.
42
+ - `connect()` raised `Unknown embedding provider` with
43
+ `ProviderConfig(provider="anthropic")` or `"gemini"`, and with OpenAI failed
44
+ unless `OPENAI_API_KEY` was exported, because the `ProviderConfig` key never
45
+ reached the embedding adapter. Without an explicit embedding provider,
46
+ OpenAI chat now uses OpenAI embeddings with the same key; other providers use
47
+ local embeddings when `nlp2sql[embeddings-local]` is installed and no
48
+ embeddings otherwise. Few-shot examples share that provider, and are skipped
49
+ with a warning when there is none.
50
+ - Correct queries came back with `is_valid=False` when they did not use the
51
+ table the heuristic intent plan guessed from the question (4 of 14 in a
52
+ sample of realistic questions), even with no semantic layer. Plan-derived
53
+ expectations are now warnings; rules from a semantic layer are still errors.
54
+ - `is_valid` was `True` for queries that write (`DELETE ...` in the default
55
+ `generate_only` mode) and for queries whose execution failed. Both are now
56
+ invalid, with the reason in the validation errors.
57
+ - The read-only check rejected valid queries with keywords inside string
58
+ literals (`WHERE name = 'Gift Set'`), and allowed functions with side effects
59
+ such as `pg_terminate_backend`, `set_config`, `nextval` or `dblink`. It now
60
+ ignores literals and rejects those functions.
61
+ - `generate_sql(max_tokens=...)` and the CLI `--max-tokens` (default 1000) also
62
+ capped the schema context sent to the model; the schema budget is now always
63
+ `NLP2SQL_MAX_SCHEMA_TOKENS`.
64
+ - `nlp2sql setup` crashed when configuring a database (it called the
65
+ nonexistent `click.choice`), and offered MySQL and SQLite, which have no
66
+ adapter. It now offers PostgreSQL and Redshift.
67
+
25
68
  ## [0.2.0rc15] - 2026-09-18
26
69
 
27
70
  ### Changed
@@ -233,6 +233,22 @@ Brief description of changes and why they're needed.
233
233
  4. **Documentation review** for user-facing changes
234
234
  5. **Merge** after approval
235
235
 
236
+ ## Releasing (maintainers)
237
+
238
+ Packages are published only from a release tag. Both publish workflows refuse to run from a branch and check that the tag name is `v` followed by the `version` in `pyproject.toml`, so the latest commit on `main` never goes to PyPI by accident.
239
+
240
+ 1. **Bump the version** in every copy and move the `CHANGELOG.md` entries from `[Unreleased]` to a new `## [X.Y.Z] - YYYY-MM-DD` section. The copies are `pyproject.toml`, `src/nlp2sql/__init__.py`, `src/nlp2sql/config/settings.py`, `mcp_server/pyproject.toml` (`[project]` and `[tool.mcp]`), `mcp_server/__init__.py` and `uv.lock` (run `uv lock`). `tests/test_version_consistency.py` fails if any of them is out of sync.
241
+ 2. **Push the bump to `main` before creating the release.** The new tag points to whatever `main` is at that moment. To check a tag name against the current version, run `python .github/scripts/verify_release_tag.py vX.Y.Z`.
242
+ 3. **Create the GitHub Release** with a new tag `vX.Y.Z` targeting `main`. Publishing the release runs "Publish Python Package to Test PyPI" on that tag automatically.
243
+ 4. **Run the integration tests locally** on the tagged commit, with the test databases running (see [Development Setup](#development-setup)).
244
+ 5. **Publish to PyPI**: in **Actions**, open **Publish Python Package to PyPI**, click **Run workflow**, pick the tag under **Use workflow from** (Tags tab) and type `PRODUCTION`. From the command line:
245
+
246
+ ```bash
247
+ gh workflow run publish-pypi.yml --ref vX.Y.Z -f confirm_production=PRODUCTION
248
+ ```
249
+
250
+ The PyPI workflow stops before building if the run is not on a tag, if the tag has no published GitHub Release, or if the tag does not match the package version. Only its final job, which runs no project code, can request a PyPI token.
251
+
236
252
  ## Enterprise Contribution Guidelines
237
253
 
238
254
  ### Performance Considerations
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nlp2sql
3
- Version: 0.2.0rc15
3
+ Version: 0.2.0rc16
4
4
  Summary: Enterprise-ready Natural Language to SQL converter with multi-provider support. Built for production scale (1000+ tables) with Clean Architecture.
5
5
  Project-URL: Homepage, https://github.com/luiscarbonel1991/nlp2sql
6
6
  Project-URL: Bug Tracker, https://github.com/luiscarbonel1991/nlp2sql/issues
@@ -36,6 +36,7 @@ Requires-Dist: psycopg2-binary>=2.9.0
36
36
  Requires-Dist: psycopg[binary]>=3.2.13
37
37
  Requires-Dist: pydantic-settings>=2.0.0
38
38
  Requires-Dist: pydantic>=2.5.0
39
+ Requires-Dist: pyyaml>=6.0
39
40
  Requires-Dist: redis>=5.0.0
40
41
  Requires-Dist: scikit-learn>=1.3.0
41
42
  Requires-Dist: sqlalchemy-redshift>=0.7.0
@@ -1,3 +1,3 @@
1
1
  """nlp2sql MCP Server - Expose nlp2sql as MCP tools."""
2
2
 
3
- __version__ = "0.2.0rc15"
3
+ __version__ = "0.2.0rc16"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nlp2sql-mcp"
3
- version = "0.2.0rc15"
3
+ version = "0.2.0rc16"
4
4
  description = "MCP server for nlp2sql - Natural Language to SQL conversion"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
@@ -21,4 +21,4 @@ build-backend = "hatchling.build"
21
21
  [tool.mcp]
22
22
  name = "nlp2sql"
23
23
  description = "Convert natural language queries to SQL using multiple AI providers"
24
- version = "0.2.0rc15"
24
+ version = "0.2.0rc16"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nlp2sql"
3
- version = "0.2.0rc15"
3
+ version = "0.2.0rc16"
4
4
  description = "Enterprise-ready Natural Language to SQL converter with multi-provider support. Built for production scale (1000+ tables) with Clean Architecture."
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -43,6 +43,7 @@ dependencies = [
43
43
  "pandas>=2.0.0",
44
44
  "greenlet>=3.2.3",
45
45
  "click>=8.0.0",
46
+ "pyyaml>=6.0",
46
47
  "psycopg[binary]>=3.2.13",
47
48
  "sqlalchemy-redshift>=0.7.0",
48
49
  ]
@@ -46,7 +46,7 @@ from .ports.semantic_validator import SemanticValidatorPort
46
46
  from .schema.example_store import ExampleStore
47
47
  from .services.query_service import QueryGenerationService
48
48
 
49
- __version__ = "0.2.0rc15"
49
+ __version__ = "0.2.0rc16"
50
50
  __author__ = "Luis Carbonel"
51
51
  __email__ = "devhighlevel@gmail.com"
52
52
 
@@ -303,9 +303,10 @@ def create_query_service(
303
303
  if embedding_provider is None:
304
304
  if embedding_provider_type is not None:
305
305
  # Explicit provider requested - raise error if dependencies missing
306
+ # Reuse the chat key (from api_key or provider_config) only when chat is also OpenAI
306
307
  embedding_provider = create_embedding_provider(
307
308
  provider=embedding_provider_type,
308
- api_key=api_key if embedding_provider_type == "openai" else None,
309
+ api_key=_api_key if embedding_provider_type == "openai" and _provider_name == "openai" else None,
309
310
  )
310
311
  else:
311
312
  # No explicit provider - try local silently, fallback to None if deps missing
@@ -602,29 +602,17 @@ def _setup_database():
602
602
  click.echo("\n[STATS] Database Configuration")
603
603
  click.echo("-" * 30)
604
604
 
605
- db_type = click.choice(["postgresql", "mysql", "sqlite"], prompt="Select database type")
605
+ # Only the databases nlp2sql has adapters for
606
+ db_type = click.prompt("Select database type", type=click.Choice(["postgresql", "redshift"]), default="postgresql")
607
+ default_port = "5432" if db_type == "postgresql" else "5439"
606
608
 
607
- if db_type == "postgresql":
608
- host = click.prompt("Host", default="localhost")
609
- port = click.prompt("Port", default="5432")
610
- username = click.prompt("Username")
611
- password = click.prompt("Password", hide_input=True)
612
- database = click.prompt("Database name")
609
+ host = click.prompt("Host", default="localhost")
610
+ port = click.prompt("Port", default=default_port)
611
+ username = click.prompt("Username")
612
+ password = click.prompt("Password", hide_input=True)
613
+ database = click.prompt("Database name")
613
614
 
614
- db_url = f"postgresql://{username}:{password}@{host}:{port}/{database}"
615
-
616
- elif db_type == "mysql":
617
- host = click.prompt("Host", default="localhost")
618
- port = click.prompt("Port", default="3306")
619
- username = click.prompt("Username")
620
- password = click.prompt("Password", hide_input=True)
621
- database = click.prompt("Database name")
622
-
623
- db_url = f"mysql://{username}:{password}@{host}:{port}/{database}"
624
-
625
- else: # sqlite
626
- db_path = click.prompt("Database file path")
627
- db_url = f"sqlite:///{db_path}"
615
+ db_url = f"{db_type}://{username}:{password}@{host}:{port}/{database}"
628
616
 
629
617
  click.echo(f"\nNote: Connection string: {db_url}")
630
618
  click.echo("Hint: Save this to your environment:")