dblift 2.1.0__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. {dblift-2.1.0 → dblift-2.2.0}/PKG-INFO +1 -1
  2. {dblift-2.1.0 → dblift-2.2.0}/cli/_command_handlers.py +3 -1
  3. {dblift-2.1.0 → dblift-2.2.0}/cli/_config_helpers.py +33 -0
  4. {dblift-2.1.0 → dblift-2.2.0}/cli/_parser_setup.py +66 -0
  5. dblift-2.2.0/cli/commands/__init__.py +1 -0
  6. dblift-2.2.0/cli/commands/config_command.py +48 -0
  7. {dblift-2.1.0 → dblift-2.2.0}/cli/main.py +19 -2
  8. {dblift-2.1.0 → dblift-2.2.0}/config/dblift_config.py +35 -50
  9. dblift-2.2.0/config/property_registry.py +135 -0
  10. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/undo_command.py +28 -258
  11. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/data_collector.py +9 -15
  12. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/PKG-INFO +1 -1
  13. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/SOURCES.txt +3 -0
  14. {dblift-2.1.0 → dblift-2.2.0}/pyproject.toml +1 -1
  15. {dblift-2.1.0 → dblift-2.2.0}/LICENSE +0 -0
  16. {dblift-2.1.0 → dblift-2.2.0}/README.md +0 -0
  17. {dblift-2.1.0 → dblift-2.2.0}/api/__init__.py +0 -0
  18. {dblift-2.1.0 → dblift-2.2.0}/api/_cli_support.py +0 -0
  19. {dblift-2.1.0 → dblift-2.2.0}/api/_client_factory.py +0 -0
  20. {dblift-2.1.0 → dblift-2.2.0}/api/_client_operations.py +0 -0
  21. {dblift-2.1.0 → dblift-2.2.0}/api/_engine_config.py +0 -0
  22. {dblift-2.1.0 → dblift-2.2.0}/api/async_client.py +0 -0
  23. {dblift-2.1.0 → dblift-2.2.0}/api/client.py +0 -0
  24. {dblift-2.1.0 → dblift-2.2.0}/api/events.py +0 -0
  25. {dblift-2.1.0 → dblift-2.2.0}/api/migrations.py +0 -0
  26. {dblift-2.1.0 → dblift-2.2.0}/api/py.typed +0 -0
  27. {dblift-2.1.0 → dblift-2.2.0}/cli/__init__.py +0 -0
  28. {dblift-2.1.0 → dblift-2.2.0}/cli/_constants.py +0 -0
  29. {dblift-2.1.0 → dblift-2.2.0}/cli/_output.py +0 -0
  30. {dblift-2.1.0 → dblift-2.2.0}/cli/db_utils.py +0 -0
  31. {dblift-2.1.0 → dblift-2.2.0}/cli/extensions.py +0 -0
  32. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/__init__.py +0 -0
  33. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/_shared.py +0 -0
  34. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/baseline.py +0 -0
  35. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/clean.py +0 -0
  36. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/import_flyway.py +0 -0
  37. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/info.py +0 -0
  38. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/migrate.py +0 -0
  39. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/repair.py +0 -0
  40. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/undo.py +0 -0
  41. {dblift-2.1.0 → dblift-2.2.0}/cli/handlers/validate.py +0 -0
  42. {dblift-2.1.0 → dblift-2.2.0}/config/__init__.py +0 -0
  43. {dblift-2.1.0 → dblift-2.2.0}/config/_credential_masking.py +0 -0
  44. {dblift-2.1.0 → dblift-2.2.0}/config/_subclasses/__init__.py +0 -0
  45. {dblift-2.1.0 → dblift-2.2.0}/config/_subclasses/dummy_config.py +0 -0
  46. {dblift-2.1.0 → dblift-2.2.0}/config/_url_builder_mixin.py +0 -0
  47. {dblift-2.1.0 → dblift-2.2.0}/config/config_builder.py +0 -0
  48. {dblift-2.1.0 → dblift-2.2.0}/config/database_config.py +0 -0
  49. {dblift-2.1.0 → dblift-2.2.0}/config/errors.py +0 -0
  50. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/__init__.py +0 -0
  51. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/_cache.py +0 -0
  52. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/_provider_base.py +0 -0
  53. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/_registry.py +0 -0
  54. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/_resolver.py +0 -0
  55. {dblift-2.1.0 → dblift-2.2.0}/config/secrets/_secrets_config.py +0 -0
  56. {dblift-2.1.0 → dblift-2.2.0}/core/__init__.py +0 -0
  57. {dblift-2.1.0 → dblift-2.2.0}/core/constants.py +0 -0
  58. {dblift-2.1.0 → dblift-2.2.0}/core/dialect_boundary.py +0 -0
  59. {dblift-2.1.0 → dblift-2.2.0}/core/exceptions.py +0 -0
  60. {dblift-2.1.0 → dblift-2.2.0}/core/features.py +0 -0
  61. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/__init__.py +0 -0
  62. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/_column_enricher.py +0 -0
  63. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/_partition_enricher.py +0 -0
  64. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/_schema_orchestrator.py +0 -0
  65. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/_utils.py +0 -0
  66. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/_vendor_property_applier.py +0 -0
  67. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/base_introspector.py +0 -0
  68. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/__init__.py +0 -0
  69. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/base_extractor.py +0 -0
  70. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/column_extractor.py +0 -0
  71. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/constraint_extractor.py +0 -0
  72. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/index_extractor.py +0 -0
  73. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/misc_extractor.py +0 -0
  74. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/procedure_extractor.py +0 -0
  75. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/sequence_extractor.py +0 -0
  76. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/table_extractor.py +0 -0
  77. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/trigger_extractor.py +0 -0
  78. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/extractors/view_extractor.py +0 -0
  79. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/introspector_factory.py +0 -0
  80. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/result.py +0 -0
  81. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/schema_introspector.py +0 -0
  82. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/vendor_queries_base.py +0 -0
  83. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/vendor_queries_factory.py +0 -0
  84. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/vendor_queries_protocols.py +0 -0
  85. {dblift-2.1.0 → dblift-2.2.0}/core/introspection/version_detector.py +0 -0
  86. {dblift-2.1.0 → dblift-2.2.0}/core/logger/__init__.py +0 -0
  87. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_base.py +0 -0
  88. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_factory.py +0 -0
  89. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_formatters.py +0 -0
  90. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_levels.py +0 -0
  91. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_multi.py +0 -0
  92. {dblift-2.1.0 → dblift-2.2.0}/core/logger/_null.py +0 -0
  93. {dblift-2.1.0 → dblift-2.2.0}/core/logger/console.py +0 -0
  94. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/__init__.py +0 -0
  95. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/_formatter_impl.py +0 -0
  96. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/diff_utils.py +0 -0
  97. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/factory.py +0 -0
  98. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/formatter.py +0 -0
  99. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/htmlformatter.py +0 -0
  100. {dblift-2.1.0 → dblift-2.2.0}/core/logger/formatters/jsonformatter.py +0 -0
  101. {dblift-2.1.0 → dblift-2.2.0}/core/logger/log.py +0 -0
  102. {dblift-2.1.0 → dblift-2.2.0}/core/logger/results.py +0 -0
  103. {dblift-2.1.0 → dblift-2.2.0}/core/migration/__init__.py +0 -0
  104. {dblift-2.1.0 → dblift-2.2.0}/core/migration/_type_match.py +0 -0
  105. {dblift-2.1.0 → dblift-2.2.0}/core/migration/clean_summary.py +0 -0
  106. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/__init__.py +0 -0
  107. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/_script_events.py +0 -0
  108. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/base_command.py +0 -0
  109. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/baseline_command.py +0 -0
  110. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/clean_command.py +0 -0
  111. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/import_flyway_command.py +0 -0
  112. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/info_command.py +0 -0
  113. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/migrate_command.py +0 -0
  114. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/repair_command.py +0 -0
  115. {dblift-2.1.0 → dblift-2.2.0}/core/migration/commands/validate_command.py +0 -0
  116. {dblift-2.1.0 → dblift-2.2.0}/core/migration/encoding.py +0 -0
  117. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/__init__.py +0 -0
  118. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/execution_engine.py +0 -0
  119. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/migration_executor.py +0 -0
  120. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/migration_helpers.py +0 -0
  121. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/placeholder_manager.py +0 -0
  122. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executor/transaction_policy.py +0 -0
  123. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executors/__init__.py +0 -0
  124. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executors/base_executor.py +0 -0
  125. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executors/executor_factory.py +0 -0
  126. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executors/python_executor.py +0 -0
  127. {dblift-2.1.0 → dblift-2.2.0}/core/migration/executors/sql_executor.py +0 -0
  128. {dblift-2.1.0 → dblift-2.2.0}/core/migration/formats/__init__.py +0 -0
  129. {dblift-2.1.0 → dblift-2.2.0}/core/migration/formats/format_detector.py +0 -0
  130. {dblift-2.1.0 → dblift-2.2.0}/core/migration/formats/migration_format.py +0 -0
  131. {dblift-2.1.0 → dblift-2.2.0}/core/migration/history/__init__.py +0 -0
  132. {dblift-2.1.0 → dblift-2.2.0}/core/migration/history/migration_history_manager.py +0 -0
  133. {dblift-2.1.0 → dblift-2.2.0}/core/migration/journals/__init__.py +0 -0
  134. {dblift-2.1.0 → dblift-2.2.0}/core/migration/journals/migration_journal.py +0 -0
  135. {dblift-2.1.0 → dblift-2.2.0}/core/migration/migration.py +0 -0
  136. {dblift-2.1.0 → dblift-2.2.0}/core/migration/placeholders/__init__.py +0 -0
  137. {dblift-2.1.0 → dblift-2.2.0}/core/migration/placeholders/placeholder_service.py +0 -0
  138. {dblift-2.1.0 → dblift-2.2.0}/core/migration/rules/__init__.py +0 -0
  139. {dblift-2.1.0 → dblift-2.2.0}/core/migration/rules/migration_rules.py +0 -0
  140. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/__init__.py +0 -0
  141. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/migration_script_manager.py +0 -0
  142. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
  143. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
  144. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
  145. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
  146. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
  147. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
  148. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_models.py +0 -0
  149. {dblift-2.1.0 → dblift-2.2.0}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
  150. {dblift-2.1.0 → dblift-2.2.0}/core/migration/sql/__init__.py +0 -0
  151. {dblift-2.1.0 → dblift-2.2.0}/core/migration/sql/execution_statement.py +0 -0
  152. {dblift-2.1.0 → dblift-2.2.0}/core/migration/sql/sql_analyzer.py +0 -0
  153. {dblift-2.1.0 → dblift-2.2.0}/core/migration/sql/sql_execution_service.py +0 -0
  154. {dblift-2.1.0 → dblift-2.2.0}/core/migration/sql/statement_splitter.py +0 -0
  155. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/__init__.py +0 -0
  156. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_data_service.py +0 -0
  157. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_display_state.py +0 -0
  158. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_formatter.py +0 -0
  159. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_state.py +0 -0
  160. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_state_manager.py +0 -0
  161. {dblift-2.1.0 → dblift-2.2.0}/core/migration/state/migration_state_service.py +0 -0
  162. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/__init__.py +0 -0
  163. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/display_formatters.py +0 -0
  164. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/migration_analyzer.py +0 -0
  165. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/migration_ui.py +0 -0
  166. {dblift-2.1.0 → dblift-2.2.0}/core/migration/ui/table_renderer.py +0 -0
  167. {dblift-2.1.0 → dblift-2.2.0}/core/migration/version_utils.py +0 -0
  168. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/__init__.py +0 -0
  169. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/data_type_normalizer.py +0 -0
  170. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/dependency_resolver.py +0 -0
  171. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/identifier_normalizer.py +0 -0
  172. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/object_orderer.py +0 -0
  173. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/type_constants.py +0 -0
  174. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/type_mapper.py +0 -0
  175. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/type_mappings.py +0 -0
  176. {dblift-2.1.0 → dblift-2.2.0}/core/normalization/type_normalizer.py +0 -0
  177. {dblift-2.1.0 → dblift-2.2.0}/core/seams/__init__.py +0 -0
  178. {dblift-2.1.0 → dblift-2.2.0}/core/seams/event_listeners.py +0 -0
  179. {dblift-2.1.0 → dblift-2.2.0}/core/seams/introspection.py +0 -0
  180. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/__init__.py +0 -0
  181. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/_base_parse_result.py +0 -0
  182. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/_base_sql_column.py +0 -0
  183. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/_base_sql_constraint.py +0 -0
  184. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/_base_sql_object.py +0 -0
  185. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/_base_sql_statement.py +0 -0
  186. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/base.py +0 -0
  187. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/constraint_validator.py +0 -0
  188. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/database_link.py +0 -0
  189. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/dialect.py +0 -0
  190. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/event.py +0 -0
  191. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/extension.py +0 -0
  192. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/foreign_data_wrapper.py +0 -0
  193. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/foreign_server.py +0 -0
  194. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/index.py +0 -0
  195. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/linked_server.py +0 -0
  196. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/module.py +0 -0
  197. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/package.py +0 -0
  198. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/partition.py +0 -0
  199. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/procedure.py +0 -0
  200. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/sequence.py +0 -0
  201. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/synonym.py +0 -0
  202. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/table.py +0 -0
  203. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/table_canonicalizer.py +0 -0
  204. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/table_options.py +0 -0
  205. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/trigger.py +0 -0
  206. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/user_defined_type.py +0 -0
  207. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/view.py +0 -0
  208. {dblift-2.1.0 → dblift-2.2.0}/core/sql_model/view_options.py +0 -0
  209. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/__init__.py +0 -0
  210. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/_partition_handler.py +0 -0
  211. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/_sqlglot_builders.py +0 -0
  212. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/base_statement_parser.py +0 -0
  213. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/base_tokenizer.py +0 -0
  214. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/common/__init__.py +0 -0
  215. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/common/base_parser.py +0 -0
  216. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/dialects/__init__.py +0 -0
  217. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/dialects/base_config.py +0 -0
  218. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/enhanced_regex_parser.py +0 -0
  219. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/hybrid_parser.py +0 -0
  220. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/parser_context.py +0 -0
  221. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/parser_factory.py +0 -0
  222. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/parser_interface.py +0 -0
  223. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/sqlglot_parser.py +0 -0
  224. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/tokens.py +0 -0
  225. {dblift-2.1.0 → dblift-2.2.0}/core/sql_parser/unified_regex_parser.py +0 -0
  226. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/__init__.py +0 -0
  227. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/_checksum_validator.py +0 -0
  228. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/_flyway_compatibility.py +0 -0
  229. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/_migration_filter.py +0 -0
  230. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/_sql_syntax_validator.py +0 -0
  231. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/_strict_mode_validator.py +0 -0
  232. {dblift-2.1.0 → dblift-2.2.0}/core/sql_validator/migration_validator.py +0 -0
  233. {dblift-2.1.0 → dblift-2.2.0}/core/state/sql_script_formatter.py +0 -0
  234. {dblift-2.1.0 → dblift-2.2.0}/core/state/sql_statement.py +0 -0
  235. {dblift-2.1.0 → dblift-2.2.0}/core/utils/__init__.py +0 -0
  236. {dblift-2.1.0 → dblift-2.2.0}/core/utils/database_url_parser.py +0 -0
  237. {dblift-2.1.0 → dblift-2.2.0}/core/utils/metadata_helpers.py +0 -0
  238. {dblift-2.1.0 → dblift-2.2.0}/core/utils/row_access.py +0 -0
  239. {dblift-2.1.0 → dblift-2.2.0}/core/utils/string_utils.py +0 -0
  240. {dblift-2.1.0 → dblift-2.2.0}/core/utils/url_masking.py +0 -0
  241. {dblift-2.1.0 → dblift-2.2.0}/db/__init__.py +0 -0
  242. {dblift-2.1.0 → dblift-2.2.0}/db/base_provider.py +0 -0
  243. {dblift-2.1.0 → dblift-2.2.0}/db/base_quirks.py +0 -0
  244. {dblift-2.1.0 → dblift-2.2.0}/db/constants.py +0 -0
  245. {dblift-2.1.0 → dblift-2.2.0}/db/dml_analysis.py +0 -0
  246. {dblift-2.1.0 → dblift-2.2.0}/db/error.py +0 -0
  247. {dblift-2.1.0 → dblift-2.2.0}/db/error_handler.py +0 -0
  248. {dblift-2.1.0 → dblift-2.2.0}/db/exceptions.py +0 -0
  249. {dblift-2.1.0 → dblift-2.2.0}/db/native_connection_manager.py +0 -0
  250. {dblift-2.1.0 → dblift-2.2.0}/db/object_naming.py +0 -0
  251. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/__init__.py +0 -0
  252. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_history_manager.py +0 -0
  253. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_locking_manager.py +0 -0
  254. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_query_executor.py +0 -0
  255. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_schema_operations.py +0 -0
  256. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_snapshot_manager.py +0 -0
  257. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/base_undo_manager.py +0 -0
  258. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/__init__.py +0 -0
  259. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/config.py +0 -0
  260. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
  261. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
  262. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
  263. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
  264. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
  265. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/query_executor.py +0 -0
  266. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
  267. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
  268. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/parser/__init__.py +0 -0
  269. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/parser/cosmosdb_regex_parser.py +0 -0
  270. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/plugin.py +0 -0
  271. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/provider.py +0 -0
  272. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/quirks.py +0 -0
  273. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/__init__.py +0 -0
  274. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_executor.py +0 -0
  275. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_executors.py +0 -0
  276. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_parsing.py +0 -0
  277. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_script_generation.py +0 -0
  278. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_translator.py +0 -0
  279. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/cosmosdb/sdk_translator/_translators.py +0 -0
  280. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/__init__.py +0 -0
  281. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/config.py +0 -0
  282. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/db2/__init__.py +0 -0
  283. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/db2/history_manager.py +0 -0
  284. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/db2/locking_manager.py +0 -0
  285. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/db2/schema_operations.py +0 -0
  286. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/introspection/__init__.py +0 -0
  287. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/parser/__init__.py +0 -0
  288. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
  289. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/parser/parser_config.py +0 -0
  290. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/plugin.py +0 -0
  291. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/provider.py +0 -0
  292. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/quirks.py +0 -0
  293. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/db2/sqlalchemy_url.py +0 -0
  294. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mariadb/__init__.py +0 -0
  295. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mariadb/plugin.py +0 -0
  296. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mariadb/provider.py +0 -0
  297. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mariadb/quirks.py +0 -0
  298. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/__init__.py +0 -0
  299. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/config.py +0 -0
  300. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/introspection/__init__.py +0 -0
  301. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/mysql/__init__.py +0 -0
  302. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/mysql/history_manager.py +0 -0
  303. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/mysql/locking_manager.py +0 -0
  304. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/mysql/schema_operations.py +0 -0
  305. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/parser/__init__.py +0 -0
  306. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
  307. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
  308. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
  309. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/parser/parser_config.py +0 -0
  310. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/plugin.py +0 -0
  311. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/provider.py +0 -0
  312. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/quirks.py +0 -0
  313. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/mysql/sqlalchemy_url.py +0 -0
  314. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/__init__.py +0 -0
  315. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/config.py +0 -0
  316. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/introspection/__init__.py +0 -0
  317. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
  318. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/oracle/__init__.py +0 -0
  319. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/oracle/dbms_output.py +0 -0
  320. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/oracle/history_manager.py +0 -0
  321. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/oracle/locking_manager.py +0 -0
  322. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/oracle/schema_operations.py +0 -0
  323. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/__init__.py +0 -0
  324. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/_comments.py +0 -0
  325. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/_object_extractor.py +0 -0
  326. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/_plsql_block.py +0 -0
  327. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/_sqlplus.py +0 -0
  328. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
  329. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/oracle_parser.py +0 -0
  330. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
  331. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
  332. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/parser_config.py +0 -0
  333. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
  334. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/plugin.py +0 -0
  335. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/provider.py +0 -0
  336. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/quirks.py +0 -0
  337. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/oracle/sqlalchemy_url.py +0 -0
  338. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/__init__.py +0 -0
  339. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/_provider_query_executor.py +0 -0
  340. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/config.py +0 -0
  341. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/introspection/__init__.py +0 -0
  342. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/parser/__init__.py +0 -0
  343. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/parser/parser_config.py +0 -0
  344. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
  345. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
  346. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
  347. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/plugin.py +0 -0
  348. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/postgresql/__init__.py +0 -0
  349. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
  350. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
  351. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
  352. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/provider.py +0 -0
  353. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/quirks.py +0 -0
  354. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
  355. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/__init__.py +0 -0
  356. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/config.py +0 -0
  357. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/introspection/__init__.py +0 -0
  358. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/parser/__init__.py +0 -0
  359. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/parser/parser_config.py +0 -0
  360. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
  361. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/plugin.py +0 -0
  362. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/provider.py +0 -0
  363. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/quirks.py +0 -0
  364. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
  365. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/__init__.py +0 -0
  366. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
  367. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
  368. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
  369. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
  370. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
  371. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/__init__.py +0 -0
  372. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/config.py +0 -0
  373. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/introspection/__init__.py +0 -0
  374. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/__init__.py +0 -0
  375. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/parser_config.py +0 -0
  376. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
  377. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
  378. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
  379. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
  380. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/plugin.py +0 -0
  381. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/provider.py +0 -0
  382. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/quirks.py +0 -0
  383. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
  384. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
  385. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
  386. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
  387. {dblift-2.1.0 → dblift-2.2.0}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
  388. {dblift-2.1.0 → dblift-2.2.0}/db/provider_capabilities.py +0 -0
  389. {dblift-2.1.0 → dblift-2.2.0}/db/provider_interfaces.py +0 -0
  390. {dblift-2.1.0 → dblift-2.2.0}/db/provider_registry.py +0 -0
  391. {dblift-2.1.0 → dblift-2.2.0}/db/sqlalchemy_provider.py +0 -0
  392. {dblift-2.1.0 → dblift-2.2.0}/db/value_utils.py +0 -0
  393. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/dependency_links.txt +0 -0
  394. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/entry_points.txt +0 -0
  395. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/requires.txt +0 -0
  396. {dblift-2.1.0 → dblift-2.2.0}/dblift.egg-info/top_level.txt +0 -0
  397. {dblift-2.1.0 → dblift-2.2.0}/integrations/__init__.py +0 -0
  398. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/__init__.py +0 -0
  399. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/_client.py +0 -0
  400. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/_engine.py +0 -0
  401. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/apps.py +0 -0
  402. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/checks.py +0 -0
  403. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/management/__init__.py +0 -0
  404. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/management/commands/__init__.py +0 -0
  405. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/management/commands/dblift_info.py +0 -0
  406. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/management/commands/dblift_migrate.py +0 -0
  407. {dblift-2.1.0 → dblift-2.2.0}/integrations/django/management/commands/dblift_validate.py +0 -0
  408. {dblift-2.1.0 → dblift-2.2.0}/integrations/fastapi.py +0 -0
  409. {dblift-2.1.0 → dblift-2.2.0}/integrations/flask.py +0 -0
  410. {dblift-2.1.0 → dblift-2.2.0}/integrations/opentelemetry.py +0 -0
  411. {dblift-2.1.0 → dblift-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dblift
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: A database migration tool that supports multiple databases with native Python drivers
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Intended Audience :: Developers
@@ -43,7 +43,9 @@ if _builtin_conflicts:
43
43
  _COMMAND_HANDLERS.update(_extension_handlers)
44
44
  del _extension_handlers, _builtin_conflicts
45
45
 
46
- _AVAILABLE_COMMANDS = list(_COMMAND_HANDLERS.keys()) + ["db"] + list(load_terminal_commands())
46
+ _AVAILABLE_COMMANDS = (
47
+ list(_COMMAND_HANDLERS.keys()) + ["db", "config"] + list(load_terminal_commands())
48
+ )
47
49
 
48
50
 
49
51
  def execute_single_command(
@@ -189,12 +189,45 @@ def _build_args_namespace(
189
189
  return args, unknown_args
190
190
 
191
191
 
192
+ # Default config filenames searched in the current working directory when no
193
+ # --config is given, in precedence order. Lets `dblift <command>` run without an
194
+ # explicit --config when a config file sits in the project root, matching the
195
+ # convention of peer tools (Alembic's alembic.ini, Flyway's flyway.conf).
196
+ _DEFAULT_CONFIG_NAMES: Tuple[str, ...] = ("dblift.yaml", "dblift.yml")
197
+
198
+
199
+ def _discover_default_config(log: Any = None) -> Optional[str]:
200
+ """Return the path to a default config file in the cwd, or None.
201
+
202
+ Searches the current working directory for the filenames in
203
+ :data:`_DEFAULT_CONFIG_NAMES` and returns the first match. Returns ``None``
204
+ when no default config is present, preserving the existing behaviour for
205
+ pure ``--db-url`` workflows.
206
+ """
207
+ cwd = Path.cwd()
208
+ for name in _DEFAULT_CONFIG_NAMES:
209
+ candidate = cwd / name
210
+ if candidate.is_file():
211
+ if log:
212
+ log.debug(f"Using discovered config file: {candidate}")
213
+ return str(candidate)
214
+ return None
215
+
216
+
192
217
  def _load_and_merge_config(args: argparse.Namespace, log: Any) -> Any:
193
218
  """Load configuration and merge database overrides from CLI arguments.
194
219
 
195
220
  Returns:
196
221
  Loaded and merged config object
197
222
  """
223
+ # Auto-discover a config file in the cwd when the user passed neither
224
+ # --config nor --db-url, so `dblift <command>` works from a project that has
225
+ # a dblift.yaml without forcing an explicit --config on every invocation.
226
+ if not getattr(args, "config", None) and not getattr(args, "database_url", None):
227
+ discovered = _discover_default_config(log)
228
+ if discovered:
229
+ args.config = discovered
230
+
198
231
  try:
199
232
  config = load_config(args.config, args)
200
233
  except (
@@ -106,6 +106,53 @@ def _make_history_table_parent() -> argparse.ArgumentParser:
106
106
  return p
107
107
 
108
108
 
109
+ def _add_registry_flags(parser: argparse.ArgumentParser) -> None:
110
+ """Emit a --flag for every registry property that lacks one.
111
+
112
+ Skips properties that are cli_only, cli_exempt, nested (database.*), or
113
+ already covered by a legacy flag recorded in cli_aliases. Ensures any NEW
114
+ persistent property added to the registry automatically gets a CLI flag,
115
+ so the CLI surface can never silently drift from config/env again.
116
+ """
117
+ from config.property_registry import PROPERTY_REGISTRY
118
+
119
+ # Collect option strings across the WHOLE tree (root + every subparser), not
120
+ # just the root parser. Many registry properties (e.g. --tags,
121
+ # --target-version, --snapshot-table) intentionally live only on specific
122
+ # subcommands; a root-only ``existing`` set would treat them as missing and
123
+ # emit a duplicate root flag, colliding with the subparser dest. This helper
124
+ # therefore runs AFTER subparsers are registered so the tree walk sees them.
125
+ existing: set[str] = set()
126
+
127
+ def _collect(p: argparse.ArgumentParser) -> None:
128
+ for action in p._actions:
129
+ existing.update(action.option_strings)
130
+ choices = getattr(action, "choices", None)
131
+ if isinstance(choices, dict):
132
+ for sub in choices.values():
133
+ if isinstance(sub, argparse.ArgumentParser):
134
+ _collect(sub)
135
+
136
+ _collect(parser)
137
+ for spec in PROPERTY_REGISTRY:
138
+ if spec.cli_only or spec.cli_exempt or "." in spec.name:
139
+ continue
140
+ if spec.cli_aliases:
141
+ continue # legacy flag (e.g. --table, --strict) already provides the surface
142
+ if spec.cli in existing:
143
+ continue
144
+ if spec.type == "bool":
145
+ parser.add_argument(
146
+ spec.cli, dest=spec.name, action="store_true", default=None, help=spec.help
147
+ )
148
+ elif spec.type == "int":
149
+ parser.add_argument(spec.cli, dest=spec.name, type=int, default=None, help=spec.help)
150
+ elif spec.type == "float":
151
+ parser.add_argument(spec.cli, dest=spec.name, type=float, default=None, help=spec.help)
152
+ else:
153
+ parser.add_argument(spec.cli, dest=spec.name, default=None, help=spec.help)
154
+
155
+
109
156
  def _make_snapshot_table_parent() -> argparse.ArgumentParser:
110
157
  """Parent parser for explicit snapshot storage commands."""
111
158
  p = argparse.ArgumentParser(add_help=False)
@@ -307,6 +354,11 @@ def create_parser(
307
354
  ),
308
355
  )
309
356
  parser.add_argument("--dry-run", action="store_true", help="Dry run mode")
357
+ parser.add_argument(
358
+ "--installed-by",
359
+ dest="installed_by",
360
+ help="Value recorded in the installed_by column (default: database username)",
361
+ )
310
362
  parser.add_argument("--log-dir", default="logs", help="Log directory")
311
363
  parser.add_argument("--log-format", default="text", help="Log format (text, json, html)")
312
364
  parser.add_argument(
@@ -404,7 +456,21 @@ def create_parser(
404
456
  db_parser = subparsers.add_parser("db", help="Database utility commands")
405
457
  db_subparsers = db_parser.add_subparsers(dest="db_command", required=True)
406
458
  setup_db_utils_parser(db_subparsers)
459
+ # Configuration introspection: `dblift config --list` prints every persistent
460
+ # property and its three surfaces (config key / env var / CLI flag). Distinct
461
+ # from the global `--config <path>` option — a subcommand named ``config`` and
462
+ # an optional ``--config`` flag do not collide in argparse.
463
+ config_parser = subparsers.add_parser("config", help="Inspect dblift configuration")
464
+ config_parser.add_argument(
465
+ "--list",
466
+ action="store_true",
467
+ help="List all properties and how to set them (config key / env var / CLI flag)",
468
+ )
407
469
  import_module("cli.extensions").load_command_extensions(parser)
470
+ # Emit registry-derived flags LAST, after every subparser (built-in and
471
+ # extension) is registered, so the tree walk in _add_registry_flags can see
472
+ # subcommand-only flags and skip them instead of shadowing them on the root.
473
+ _add_registry_flags(parser)
408
474
  if suppress_errors:
409
475
  all_subparsers = [
410
476
  migrate_parser,
@@ -0,0 +1 @@
1
+ """First-party CLI command handlers that own their own dispatch."""
@@ -0,0 +1,48 @@
1
+ """``dblift config --list`` — print every persistent property and its surfaces."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, List
6
+
7
+ from config.property_registry import PROPERTY_REGISTRY, PropertySpec
8
+ from core.logger.console import render_records_table
9
+
10
+
11
+ def _cli_display(spec: PropertySpec) -> str:
12
+ """The real CLI flag for a property: '(none)' if cli-exempt, the legacy
13
+ alias if one is registered, else the derived flag."""
14
+ if spec.cli_exempt:
15
+ return "(none)"
16
+ if spec.cli_aliases:
17
+ return str(spec.cli_aliases[0])
18
+ return spec.cli
19
+
20
+
21
+ def build_property_table() -> List[Dict[str, str]]:
22
+ """Return one row per registry property with its config key, env var, CLI flag, and default."""
23
+ rows: List[Dict[str, str]] = []
24
+ for spec in PROPERTY_REGISTRY:
25
+ rows.append(
26
+ {
27
+ "name": spec.name,
28
+ "config": spec.name,
29
+ "env": spec.env,
30
+ "cli": _cli_display(spec),
31
+ "default": "" if spec.default is None else str(spec.default),
32
+ }
33
+ )
34
+ return rows
35
+
36
+
37
+ def run_config_command(args: Any) -> int:
38
+ """Print the property/env/CLI surface table for ``dblift config --list``; return 0."""
39
+ rows = build_property_table()
40
+ table = render_records_table(
41
+ [("PROPERTY", "left"), ("ENV VAR", "left"), ("CLI FLAG", "left")],
42
+ [[r["name"], r["env"], r["cli"]] for r in rows],
43
+ title="dblift configuration properties",
44
+ )
45
+ print(
46
+ table
47
+ ) # lint: allow-print config --list self-documentation (pre-CommandOutput short-circuit)
48
+ return 0
@@ -102,6 +102,16 @@ _GLOBAL_ONLY_ARGS: List[str] = [
102
102
  "--quiet",
103
103
  "-q",
104
104
  "--no-progress",
105
+ # Root-only value flags surfaced from the PropertySpec registry
106
+ # (installed_by is added directly; max_snapshots is generated by
107
+ # _add_registry_flags). They live only on the root parser, so — like the
108
+ # other root-only value flags above — they must be classified global or the
109
+ # argv preprocessor relocates them past the subcommand token and the
110
+ # subparser rejects them as "unrecognized arguments". Covered by
111
+ # tests/unit/cli/test_global_only_args_completeness.py.
112
+ "--installed-by",
113
+ "--max-snapshots",
114
+ "--snapshot-table",
105
115
  ]
106
116
 
107
117
  # Tool-level flag aliases for subcommands that take their own version-like
@@ -227,6 +237,15 @@ def _parse_argv_and_load_config(argv: List[str]) -> _CliContext:
227
237
  if not commands and hasattr(args, "command"):
228
238
  commands = [args.command]
229
239
 
240
+ # `dblift config --list` is offline self-documentation: it reads only the
241
+ # property registry, so it short-circuits here — before any config/db load —
242
+ # exactly like the `db` subcommand path below. Listing is the command's only
243
+ # behaviour today, so it runs whether or not --list was passed.
244
+ if commands and commands[0] == "config":
245
+ from cli.commands.config_command import run_config_command
246
+
247
+ sys.exit(run_config_command(args))
248
+
230
249
  log = LogFactory.get_log("Dblift")
231
250
  parser = create_parser()
232
251
  # Validate log format before any config load so bogus --log-format fails with argparse
@@ -316,7 +335,6 @@ def _dispatch_command(ctx: _CliContext, command_output: CommandOutput) -> int:
316
335
  ctx.log.debug(f"Using placeholders: {placeholders}")
317
336
 
318
337
  ctx.config.journal_enabled = True
319
- ctx.config.journal_dir = None
320
338
  if getattr(ctx.args, "strict", False):
321
339
  ctx.config.strict_mode = True
322
340
  ctx.log.info(
@@ -382,7 +400,6 @@ def _dispatch_command(ctx: _CliContext, command_output: CommandOutput) -> int:
382
400
  recursive=recursive,
383
401
  placeholders=placeholders,
384
402
  dir_recursive_map=dir_recursive_map,
385
- license_tier=_resolve_license_tier(ctx.args),
386
403
  )
387
404
  if not success:
388
405
  any_command_failed = True
@@ -285,7 +285,6 @@ class DbliftConfig:
285
285
  1 # Maximum number of snapshots to keep (oldest are deleted when limit exceeded)
286
286
  )
287
287
  journal_enabled: bool = True
288
- journal_dir: Optional[str] = None
289
288
 
290
289
  # Error handling and retry configuration
291
290
  error_handling_enabled: bool = True
@@ -572,8 +571,8 @@ class DbliftConfig:
572
571
  migrations_directories = migrations.get("directories", [])
573
572
  migrations_recursive = migrations.get("recursive", True)
574
573
 
575
- # Journal settings are always in-memory only - ignore journal_dir if set in config files
576
- # journal_enabled defaults to True, journal_dir defaults to None (will be enforced in cli/main.py)
574
+ # Journal settings are always in-memory only
575
+ # journal_enabled defaults to True
577
576
  config = cls(
578
577
  database=database_config,
579
578
  migrations=MigrationsConfig(
@@ -614,8 +613,6 @@ class DbliftConfig:
614
613
  log_level=data.get("log_level"),
615
614
  secrets=secrets_config,
616
615
  )
617
- # Explicitly ensure journal_dir is None (journal is always in-memory only)
618
- config.journal_dir = None
619
616
  config.log_dir = root_log_dir
620
617
  return config
621
618
 
@@ -699,7 +696,11 @@ class DbliftConfig:
699
696
  # cannot pollute or shadow legitimate config fields.
700
697
  #
701
698
  # Names whose env-var suffix differs from the config field name
702
- _DB_ALIASES: Dict[str, str] = {"USER": "username", "SESSION_VARS": "session_variables"}
699
+ _DB_ALIASES: Dict[str, str] = {
700
+ "USER": "username",
701
+ "USERNAME": "username",
702
+ "SESSION_VARS": "session_variables",
703
+ }
703
704
  # Suffixes that require structured (JSON / k=v CSV) parsing into a dict
704
705
  _STRUCTURED = {"OPTIONS", "SESSION_VARS", "EXTRA_PARAMS", "PROPERTIES"}
705
706
  # Suffixes whose value must be coerced to int
@@ -719,6 +720,7 @@ class DbliftConfig:
719
720
  | {
720
721
  "URL",
721
722
  "USER",
723
+ "USERNAME",
722
724
  "PASSWORD",
723
725
  "SCHEMA",
724
726
  "HOST",
@@ -776,19 +778,23 @@ class DbliftConfig:
776
778
  config: Dict[str, Any] = {}
777
779
  if db:
778
780
  config["database"] = db
779
- if env.get("DBLIFT_SNAPSHOT_TABLE"):
780
- config["snapshot_table"] = env["DBLIFT_SNAPSHOT_TABLE"]
781
- if env.get("DBLIFT_HISTORY_TABLE"):
782
- config["history_table"] = env["DBLIFT_HISTORY_TABLE"]
783
- if env.get("DBLIFT_MAX_SNAPSHOTS"):
784
- try:
785
- config["max_snapshots"] = int(env["DBLIFT_MAX_SNAPSHOTS"])
786
- except ValueError:
787
- if diagnostics is not None:
788
- diagnostics.invalid_int_vars.append("DBLIFT_MAX_SNAPSHOTS")
789
- pass # Ignore invalid values
790
- if env.get("DBLIFT_CLEAN_DISABLED"):
791
- config["clean_disabled"] = env["DBLIFT_CLEAN_DISABLED"].lower() in ("1", "true", "yes")
781
+
782
+ from config.property_registry import PROPERTY_REGISTRY
783
+
784
+ for spec in PROPERTY_REGISTRY:
785
+ if spec.cli_only or "." in spec.name:
786
+ continue # nested database.* fields are handled by the DBLIFT_DB_* loop above
787
+ raw = env.get(spec.env)
788
+ if not raw:
789
+ continue
790
+ if spec.coerce is not None:
791
+ try:
792
+ config[spec.name] = spec.coerce(raw)
793
+ except (ValueError, TypeError):
794
+ if diagnostics is not None:
795
+ diagnostics.invalid_int_vars.append(spec.env)
796
+ else:
797
+ config[spec.name] = raw
792
798
  return config
793
799
 
794
800
  @classmethod
@@ -849,34 +855,16 @@ class DbliftConfig:
849
855
  if db_cfg:
850
856
  config["database"] = db_cfg
851
857
 
852
- for key in (
853
- "snapshot_table",
854
- "history_table",
855
- "max_snapshots",
856
- "baseline_version",
857
- "target_version",
858
- "dry_run",
859
- "undo",
860
- "installed_by",
861
- "mark_as_executed",
862
- "strict_mode",
863
- "clean_disabled",
864
- "journal_enabled",
865
- "error_handling_enabled",
866
- "max_retries",
867
- "retry_delay",
868
- "retry_backoff",
869
- "retry_jitter",
870
- "retryable_error_categories",
871
- "tags",
872
- "exclude_tags",
873
- "versions",
874
- "exclude_versions",
875
- "log_file",
876
- "log_dir",
877
- "log_format",
878
- "log_level",
879
- ):
858
+ from config.property_registry import PROPERTY_REGISTRY
859
+
860
+ # Registry covers the persistent scalar properties; these three are
861
+ # arg-only keys not modeled in the registry (undo is subcommand-driven,
862
+ # journal_enabled/retryable_error_categories are non-scalar/internal).
863
+ _arg_only_keys = ("undo", "journal_enabled", "retryable_error_categories")
864
+ registry_keys = [
865
+ spec.name for spec in PROPERTY_REGISTRY if not spec.cli_only and "." not in spec.name
866
+ ]
867
+ for key in (*registry_keys, *_arg_only_keys):
880
868
  if key in args and args[key] not in (None, ""):
881
869
  config[key] = args[key]
882
870
 
@@ -1019,9 +1007,6 @@ class DbliftConfig:
1019
1007
  if self.placeholders:
1020
1008
  result["placeholders"] = self.placeholders
1021
1009
 
1022
- if self.journal_dir:
1023
- result["journal_dir"] = self.journal_dir
1024
-
1025
1010
  if self.log_dir:
1026
1011
  result["log_dir"] = self.log_dir
1027
1012
 
@@ -0,0 +1,135 @@
1
+ """Single source of truth for every persistent dblift property.
2
+
3
+ Each :class:`PropertySpec` mechanically derives its environment variable and
4
+ CLI flag from its dotted config name, so a property can never be added to one
5
+ surface and silently missing from another. See
6
+ ``tests/unit/config/test_property_parity.py`` (added in a later task) for the
7
+ invariant that enforces this across ``from_env_dict`` / ``from_args_dict`` /
8
+ ``to_dict`` / the CLI parser.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from typing import Callable, List, Optional
15
+
16
+
17
+ def env_name(name: str) -> str:
18
+ """Derive the env var: ``database.username`` -> ``DBLIFT_DB_USERNAME``."""
19
+ if name.startswith("database."):
20
+ name = "db_" + name[len("database.") :]
21
+ return "DBLIFT_" + name.replace(".", "_").upper()
22
+
23
+
24
+ def cli_flag(name: str) -> str:
25
+ """Derive the CLI flag: ``database.username`` -> ``--db-username``."""
26
+ if name.startswith("database."):
27
+ name = "db_" + name[len("database.") :]
28
+ return "--" + name.replace(".", "_").replace("_", "-")
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class PropertySpec:
33
+ name: str # dotted config key; "database.<field>" for nested db config
34
+ type: str # "str" | "int" | "float" | "bool" | "dict" | "list"
35
+ default: object = None
36
+ cli_only: bool = False # runtime meta-flags (version/quiet/...) — no env/config
37
+ cli_exempt: bool = False # has env+config but intentionally no CLI flag
38
+ cli_aliases: tuple = () # legacy flag names that already provide this CLI surface
39
+ coerce: Optional[Callable[[str], object]] = None
40
+ help: str = ""
41
+
42
+ @property
43
+ def env(self) -> str:
44
+ return env_name(self.name)
45
+
46
+ @property
47
+ def cli(self) -> str:
48
+ return cli_flag(self.name)
49
+
50
+
51
+ def _bool(v: str) -> bool:
52
+ return v.lower() in ("1", "true", "yes")
53
+
54
+
55
+ # NOTE: keep this list the ONLY place persistent properties are declared.
56
+ # Structured db fields (extra_params, properties, options, session_variables)
57
+ # and CosmosDB-specific fields keep their existing bespoke env/arg parsing and
58
+ # are intentionally EXCLUDED here.
59
+ PROPERTY_REGISTRY: List[PropertySpec] = [
60
+ # --- dblift-managed tables ---
61
+ PropertySpec(
62
+ "history_table",
63
+ "str",
64
+ "dblift_schema_history",
65
+ cli_aliases=("--table",),
66
+ help="dblift schema-history table name",
67
+ ),
68
+ PropertySpec(
69
+ "snapshot_table",
70
+ "str",
71
+ "dblift_schema_snapshots",
72
+ help="dblift schema-snapshots table name",
73
+ ),
74
+ PropertySpec("max_snapshots", "int", 1, coerce=int, help="Max snapshots to retain"),
75
+ # --- audit / execution ---
76
+ PropertySpec(
77
+ "installed_by",
78
+ "str",
79
+ None,
80
+ help="Value recorded in the installed_by column (default: db username)",
81
+ ),
82
+ PropertySpec("baseline_version", "str", None),
83
+ PropertySpec("target_version", "str", None),
84
+ PropertySpec("mark_as_executed", "bool", False, coerce=_bool),
85
+ PropertySpec("strict_mode", "bool", False, coerce=_bool, cli_aliases=("--strict",)),
86
+ PropertySpec("clean_disabled", "bool", True, coerce=_bool),
87
+ PropertySpec("dry_run", "bool", False, coerce=_bool),
88
+ # --- migration selection ---
89
+ PropertySpec("tags", "str", None),
90
+ PropertySpec("exclude_tags", "str", None),
91
+ PropertySpec("versions", "str", None),
92
+ PropertySpec("exclude_versions", "str", None),
93
+ # --- retry / error handling (config+env, no CLI flag) ---
94
+ PropertySpec("error_handling_enabled", "bool", True, coerce=_bool, cli_exempt=True),
95
+ PropertySpec("max_retries", "int", 3, coerce=int, cli_exempt=True),
96
+ PropertySpec("retry_delay", "float", 1.0, coerce=float, cli_exempt=True),
97
+ PropertySpec("retry_backoff", "float", 2.0, coerce=float, cli_exempt=True),
98
+ PropertySpec("retry_jitter", "float", 0.2, coerce=float, cli_exempt=True),
99
+ # --- logging ---
100
+ PropertySpec("log_level", "str", None),
101
+ PropertySpec("log_format", "str", None),
102
+ PropertySpec("log_file", "str", None),
103
+ PropertySpec("log_dir", "str", None),
104
+ # --- database connection (nested under database.*) ---
105
+ # NOTE: the env/args generators skip dotted (database.*) names. These fields
106
+ # are read by the pre-existing DBLIFT_DB_* machinery in DbliftConfig
107
+ # (_DB_ALIASES / _ALLOWED), which also handles the structured/aliased/CosmosDB
108
+ # cases the registry does not model. Listing them here is NOT redundant: the
109
+ # parity tests validate each one's surfaces, so adding a new database.* field
110
+ # without a corresponding DBLIFT_DB_* allowlist entry fails CI loudly rather
111
+ # than silently dropping the surface. Drift is detected, not eliminated, for
112
+ # these fields.
113
+ PropertySpec("database.url", "str", ""),
114
+ PropertySpec("database.type", "str", None, cli_exempt=True),
115
+ PropertySpec("database.username", "str", ""),
116
+ PropertySpec("database.password", "str", ""),
117
+ PropertySpec("database.schema", "str", ""),
118
+ PropertySpec("database.host", "str", None, cli_exempt=True),
119
+ PropertySpec("database.port", "int", None, coerce=int, cli_exempt=True),
120
+ PropertySpec("database.database", "str", None, cli_exempt=True),
121
+ PropertySpec("database.connection_timeout", "int", 30, coerce=int, cli_exempt=True),
122
+ ]
123
+
124
+
125
+ def spec_for(name: str) -> Optional[PropertySpec]:
126
+ """Return the :class:`PropertySpec` for ``name``, or ``None`` if unknown.
127
+
128
+ Runtime-only meta flags (``--version``, ``--quiet``, ``--config`` …) are not
129
+ persistent properties and are intentionally absent from the registry, so
130
+ ``spec_for("version")`` returns ``None`` by design.
131
+ """
132
+ for spec in PROPERTY_REGISTRY:
133
+ if spec.name == name:
134
+ return spec
135
+ return None