databricks-labs-lakebridge 0.10.0__tar.gz → 0.10.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/PKG-INFO +5 -5
  2. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/README.md +1 -1
  3. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/__about__.py +1 -1
  4. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/base_install.py +2 -1
  5. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/cli.py +30 -6
  6. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/config.py +7 -7
  7. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/recon.py +2 -1
  8. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/file_utils.py +0 -11
  9. databricks_labs_lakebridge-0.10.2/databricks/labs/lakebridge/helpers/string_utils.py +28 -0
  10. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/install.py +46 -23
  11. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/intermediate/root_tables.py +5 -7
  12. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/execute.py +60 -46
  13. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/lsp/lsp_engine.py +1 -3
  14. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/uninstall.py +1 -1
  15. databricks_labs_lakebridge-0.10.2/docs/lakebridge/src/theme/DocSidebarItems/index.tsx +42 -0
  16. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/pyproject.toml +3 -3
  17. databricks_labs_lakebridge-0.10.0/databricks/labs/lakebridge/helpers/string_utils.py +0 -62
  18. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/.gitignore +0 -0
  19. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/LICENSE +0 -0
  20. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/NOTICE +0 -0
  21. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/__init__.py +0 -0
  22. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/__init__.py +0 -0
  23. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/__init__.py +0 -0
  24. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/assessments/configure_assessment.py +0 -0
  25. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/assessments/pipeline.py +0 -0
  26. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/assessments/profiler_config.py +0 -0
  27. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/connections/__init__.py +0 -0
  28. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/connections/credential_manager.py +0 -0
  29. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/connections/database_manager.py +0 -0
  30. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/connections/env_getter.py +0 -0
  31. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/contexts/__init__.py +0 -0
  32. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/contexts/application.py +0 -0
  33. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/__init__.py +0 -0
  34. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/commons.py +0 -0
  35. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/lakebridge_snow_transpilation_coverage.py +0 -0
  36. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/local_report.py +0 -0
  37. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/sqlglot_snow_transpilation_coverage.py +0 -0
  38. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/coverage/sqlglot_tsql_transpilation_coverage.py +0 -0
  39. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/__init__.py +0 -0
  40. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/configurator.py +0 -0
  41. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/dashboard.py +0 -0
  42. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/installation.py +0 -0
  43. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/job.py +0 -0
  44. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/table.py +0 -0
  45. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/deployment/upgrade_common.py +0 -0
  46. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/discovery/table.py +0 -0
  47. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/discovery/table_definition.py +0 -0
  48. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/discovery/tsql_table_definition.py +0 -0
  49. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/errors/exceptions.py +0 -0
  50. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/__init__.py +0 -0
  51. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/db_sql.py +0 -0
  52. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/execution_time.py +0 -0
  53. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/metastore.py +0 -0
  54. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/recon_config_utils.py +0 -0
  55. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/telemetry_utils.py +0 -0
  56. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/helpers/validation.py +0 -0
  57. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/intermediate/__init__.py +0 -0
  58. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/intermediate/dag.py +0 -0
  59. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/intermediate/engine_adapter.py +0 -0
  60. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/jvmproxy.py +0 -0
  61. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/lineage.py +0 -0
  62. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/__init__.py +0 -0
  63. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/compare.py +0 -0
  64. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/__init__.py +0 -0
  65. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/data_source.py +0 -0
  66. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/databricks.py +0 -0
  67. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/jdbc_reader.py +0 -0
  68. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/oracle.py +0 -0
  69. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/secrets.py +0 -0
  70. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/snowflake.py +0 -0
  71. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/source_adapter.py +0 -0
  72. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/connectors/sql_server.py +0 -0
  73. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/constants.py +0 -0
  74. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/exception.py +0 -0
  75. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/execute.py +0 -0
  76. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/__init__.py +0 -0
  77. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/aggregate_query.py +0 -0
  78. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/base.py +0 -0
  79. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/count_query.py +0 -0
  80. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/expression_generator.py +0 -0
  81. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/hash_query.py +0 -0
  82. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/sampling_query.py +0 -0
  83. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/query_builder/threshold_query.py +0 -0
  84. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/recon_capture.py +0 -0
  85. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/recon_config.py +0 -0
  86. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/recon_output_config.py +0 -0
  87. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/runner.py +0 -0
  88. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/sampler.py +0 -0
  89. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/reconcile/schema_compare.py +0 -0
  90. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/__init__.py +0 -0
  91. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/config/credentials.yml +0 -0
  92. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/__init__.py +0 -0
  93. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/__init__.py +0 -0
  94. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/00_0_aggregate_recon_header.md +0 -0
  95. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/01_0_recon_id.filter.yml +0 -0
  96. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/01_1_executed_by.filter.yml +0 -0
  97. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/01_2_started_at.filter.yml +0 -0
  98. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/02_0_source_type.filter.yml +0 -0
  99. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/02_1_source_table.filter.yml +0 -0
  100. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/02_2_target_table.filter.yml +0 -0
  101. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/04_0_aggregate_summary_table.sql +0 -0
  102. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/05_0_aggregate_recon_drilldown_header.md +0 -0
  103. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/06_0_recon_id.filter.yml +0 -0
  104. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/06_1_category.filter.yml +0 -0
  105. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/06_2_aggregate_type.filter.yml +0 -0
  106. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/07_0_target_table.filter.yml +0 -0
  107. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/07_1_source_table.filter.yml +0 -0
  108. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/08_0_aggregate_details_table.sql +0 -0
  109. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/09_0_aggregate_missing_mismatch_header.md +0 -0
  110. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/10_0_aggr_mismatched_records.sql +0 -0
  111. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/11_0_aggr_missing_in_databricks.sql +0 -0
  112. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/11_1_aggr_missing_in_source.sql +0 -0
  113. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/aggregate_reconciliation_metrics/dashboard.yml +0 -0
  114. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/00_0_recon_main.md +0 -0
  115. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/01_0_recon_id.filter.yml +0 -0
  116. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/01_1_report_type.filter.yml +0 -0
  117. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/01_2_executed_by.filter.yml +0 -0
  118. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/02_0_source_type.filter.yml +0 -0
  119. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/02_1_source_table.filter.yml +0 -0
  120. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/02_2_target_table.filter.yml +0 -0
  121. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/03_0_started_at.filter.yml +0 -0
  122. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/05_0_summary_table.sql +0 -0
  123. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/06_0_schema_comparison_header.md +0 -0
  124. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/07_0_schema_details_table.sql +0 -0
  125. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/08_0_drill_down_header.md +0 -0
  126. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/09_0_recon_id.filter.yml +0 -0
  127. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/09_1_category.filter.yml +0 -0
  128. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/10_0_target_table.filter.yml +0 -0
  129. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/10_1_source_table.filter.yml +0 -0
  130. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/11_0_recon_details_pivot.sql +0 -0
  131. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/12_0_daily_data_validation_issue_header.md +0 -0
  132. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/13_0_success_fail_.filter.yml +0 -0
  133. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/14_0_failed_recon_ids.sql +0 -0
  134. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/15_0_total_failed_runs.sql +0 -0
  135. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/15_1_failed_targets.sql +0 -0
  136. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/15_2_successful_targets.sql +0 -0
  137. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/16_0_missing_mismatch_header.md +0 -0
  138. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/17_0_mismatched_records.sql +0 -0
  139. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/17_1_threshold_mismatches.sql +0 -0
  140. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/18_0_missing_in_databricks.sql +0 -0
  141. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/18_1_missing_in_source.sql +0 -0
  142. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/dashboards/reconciliation_metrics/dashboard.yml +0 -0
  143. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/__init__.py +0 -0
  144. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/__init__.py +0 -0
  145. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/aggregate_details.sql +0 -0
  146. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/aggregate_metrics.sql +0 -0
  147. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/aggregate_rules.sql +0 -0
  148. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/details.sql +0 -0
  149. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/main.sql +0 -0
  150. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/resources/reconcile/queries/installation/metrics.sql +0 -0
  151. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/__init__.py +0 -0
  152. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/lsp/__init__.py +0 -0
  153. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/__init__.py +0 -0
  154. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/dialect_utils.py +0 -0
  155. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/generator/__init__.py +0 -0
  156. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/generator/databricks.py +0 -0
  157. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/lca_utils.py +0 -0
  158. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/local_expression.py +0 -0
  159. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/parsers/__init__.py +0 -0
  160. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/parsers/oracle.py +0 -0
  161. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/parsers/presto.py +0 -0
  162. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/parsers/snowflake.py +0 -0
  163. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/sqlglot/sqlglot_engine.py +0 -0
  164. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/transpile_engine.py +0 -0
  165. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/transpiler/transpile_status.py +0 -0
  166. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/upgrades/v0.4.0_add_main_table_operation_name_column.py +0 -0
  167. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/databricks/labs/lakebridge/upgrades/v0.6.0_alter_metrics_datatype.py +0 -0
  168. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/components/Button.tsx +0 -0
  169. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/css/custom.css +0 -0
  170. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/css/table.css +0 -0
  171. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/pages/index.tsx +0 -0
  172. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/theme/Footer/index.tsx +0 -0
  173. {databricks_labs_lakebridge-0.10.0 → databricks_labs_lakebridge-0.10.2}/docs/lakebridge/src/theme/Layout/index.tsx +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-labs-lakebridge
3
- Version: 0.10.0
3
+ Version: 0.10.2
4
4
  Summary: Fast and predictable migrations to Databricks Lakehouse Platform. This tool is designed to help you migrate your data and workloads to the Databricks Lakehouse Platform in a fast, predictable, and reliable way. It provides a set of tools and utilities to help you reconcile your data and workloads, assess your current state, and plan your migration.
5
- Project-URL: Documentation, https://github.com/databrickslabs/lakebridge
5
+ Project-URL: Documentation, https://databrickslabs.github.io/lakebridge
6
6
  Project-URL: Issues, https://github.com/databrickslabs/lakebridge/issues
7
7
  Project-URL: Source, https://github.com/databrickslabs/lakebridge
8
8
  Maintainer-email: Databricks Labs <labs-oss@databricks.com>
@@ -25,8 +25,8 @@ Classifier: Topic :: Software Development :: Libraries
25
25
  Classifier: Topic :: Utilities
26
26
  Requires-Python: >=3.10
27
27
  Requires-Dist: cryptography<45.1.0,>=44.0.2
28
- Requires-Dist: databricks-bb-analyzer~=0.1.6
29
- Requires-Dist: databricks-labs-blueprint[yaml]<0.12.0,>=0.11.0
28
+ Requires-Dist: databricks-bb-analyzer~=0.1.8
29
+ Requires-Dist: databricks-labs-blueprint[yaml]<0.12.0,>=0.11.1
30
30
  Requires-Dist: databricks-labs-lsql==0.16.0
31
31
  Requires-Dist: databricks-sdk~=0.51.0
32
32
  Requires-Dist: duckdb~=1.2.2
@@ -42,7 +42,7 @@ Databricks Labs Lakebridge
42
42
  ![Databricks Labs Lakebridge White](/docs/lakebridge/static/img/lakebridge-lockup-white-background.svg)
43
43
 
44
44
 
45
- [![build](https://github.com/databrickslabs/remorph/actions/workflows/push.yml/badge.svg)](https://github.com/databrickslabs/remorph/actions/workflows/push.yml)
45
+ [![build](https://github.com/databrickslabs/lakebridge/actions/workflows/push.yml/badge.svg)](https://github.com/databrickslabs/remorph/actions/workflows/push.yml)
46
46
  ![PyPI - Downloads](https://img.shields.io/pypi/dm/databricks-labs-remorph?cacheSeconds=3600)
47
47
 
48
48
  -----
@@ -3,7 +3,7 @@ Databricks Labs Lakebridge
3
3
  ![Databricks Labs Lakebridge White](/docs/lakebridge/static/img/lakebridge-lockup-white-background.svg)
4
4
 
5
5
 
6
- [![build](https://github.com/databrickslabs/remorph/actions/workflows/push.yml/badge.svg)](https://github.com/databrickslabs/remorph/actions/workflows/push.yml)
6
+ [![build](https://github.com/databrickslabs/lakebridge/actions/workflows/push.yml/badge.svg)](https://github.com/databrickslabs/remorph/actions/workflows/push.yml)
7
7
  ![PyPI - Downloads](https://img.shields.io/pypi/dm/databricks-labs-remorph?cacheSeconds=3600)
8
8
 
9
9
  -----
@@ -1,2 +1,2 @@
1
1
  # DO NOT MODIFY THIS FILE
2
- __version__ = "0.10.0"
2
+ __version__ = "0.10.2"
@@ -9,4 +9,5 @@ if __name__ == "__main__":
9
9
  logger = get_logger(__file__)
10
10
  logger.setLevel("INFO")
11
11
 
12
- logger.info("Successfully Setup Remorph Components Locally")
12
+ logger.info("Successfully Setup Lakebridge Components Locally")
13
+ logger.info("For more information, please visit https://databrickslabs.github.io/lakebridge/")
@@ -1,6 +1,8 @@
1
1
  import asyncio
2
2
  import dataclasses
3
+ import itertools
3
4
  import json
5
+ import logging
4
6
  import os
5
7
  import time
6
8
  from pathlib import Path
@@ -11,7 +13,7 @@ from databricks.sdk.service.sql import CreateWarehouseRequestWarehouseType
11
13
  from databricks.sdk import WorkspaceClient
12
14
 
13
15
  from databricks.labs.blueprint.cli import App
14
- from databricks.labs.blueprint.entrypoint import get_logger
16
+ from databricks.labs.blueprint.entrypoint import get_logger, is_in_debug
15
17
  from databricks.labs.blueprint.installation import JsonValue
16
18
  from databricks.labs.blueprint.tui import Prompts
17
19
 
@@ -40,6 +42,7 @@ from databricks.labs.lakebridge.transpiler.lsp.lsp_engine import LSPConfig
40
42
  from databricks.labs.lakebridge.transpiler.sqlglot.sqlglot_engine import SqlglotEngine
41
43
  from databricks.labs.lakebridge.transpiler.transpile_engine import TranspileEngine
42
44
 
45
+ from databricks.labs.lakebridge.transpiler.transpile_status import ErrorSeverity
43
46
 
44
47
  lakebridge = App(__file__)
45
48
  logger = get_logger(__file__)
@@ -189,7 +192,7 @@ class _TranspileConfigChecker:
189
192
  transpiler_name = self._prompts.choice("Select the transpiler:", list(transpiler_names))
190
193
  else:
191
194
  transpiler_name = next(name for name in transpiler_names)
192
- logger.info(f"lakebridge will use the {transpiler_name} transpiler")
195
+ logger.info(f"Lakebridge will use the {transpiler_name} transpiler")
193
196
  transpiler_config_path = str(TranspilerInstaller.transpiler_config_path(transpiler_name))
194
197
  logger.debug(f"Setting transpiler_config_path to '{transpiler_config_path}'")
195
198
  self._config = dataclasses.replace(self._config, transpiler_config_path=cast(str, transpiler_config_path))
@@ -306,11 +309,29 @@ async def _transpile(ctx: ApplicationContext, config: TranspileConfig, engine: T
306
309
  logger.debug(f"User: {user}")
307
310
  _override_workspace_client_config(ctx, config.sdk_config)
308
311
  status, errors = await do_transpile(ctx.workspace_client, engine, config)
309
- for error in errors:
310
- logger.error(f"Error Transpiling: {str(error)}")
312
+
313
+ logger.debug(f"Transpilation completed with status: {status}")
314
+
315
+ for path, errors_by_path in itertools.groupby(errors, key=lambda x: x.path):
316
+ errs = list(errors_by_path)
317
+ errors_by_severity = {
318
+ severity.name: len(list(errors)) for severity, errors in itertools.groupby(errs, key=lambda x: x.severity)
319
+ }
320
+ reports = []
321
+ reported_severities = [ErrorSeverity.ERROR, ErrorSeverity.WARNING]
322
+ for severity in reported_severities:
323
+ if severity.name in errors_by_severity:
324
+ word = str.lower(severity.name) + "s" if errors_by_severity[severity.name] > 1 else ""
325
+ reports.append(f"{errors_by_severity[severity.name]} {word}")
326
+
327
+ msg = ", ".join(reports) + " found"
328
+
329
+ if ErrorSeverity.ERROR.name in errors_by_severity:
330
+ logger.error(f"{path}: {msg}")
331
+ elif ErrorSeverity.WARNING.name in errors_by_severity:
332
+ logger.warning(f"{path}: {msg}")
311
333
 
312
334
  # Table Template in labs.yml requires the status to be list of dicts Do not change this
313
- logger.info(f"lakebridge Transpiler encountered {len(status)} from given {config.input_source} files.")
314
335
  return [status]
315
336
 
316
337
 
@@ -442,8 +463,11 @@ def analyze(w: WorkspaceClient, source_directory: str, report_file: str):
442
463
  with_user_agent_extra("analyzer_source_tech", make_alphanum_or_semver(source_tech))
443
464
  user = ctx.current_user
444
465
  logger.debug(f"User: {user}")
445
- Analyzer.analyze(Path(input_folder), Path(output_file), source_tech)
466
+ is_debug = logger.getEffectiveLevel() == logging.DEBUG
467
+ Analyzer.analyze(Path(input_folder), Path(output_file), source_tech, is_debug=is_debug)
446
468
 
447
469
 
448
470
  if __name__ == "__main__":
449
471
  lakebridge()
472
+ if is_in_debug():
473
+ logger.setLevel(logging.DEBUG)
@@ -4,7 +4,7 @@ import logging
4
4
  from dataclasses import dataclass
5
5
  from enum import Enum, auto
6
6
  from pathlib import Path
7
- from typing import Any, cast
7
+ from typing import Any, Literal, cast
8
8
 
9
9
  from databricks.labs.blueprint.installation import JsonValue
10
10
  from databricks.labs.blueprint.tui import Prompts
@@ -89,30 +89,30 @@ class TranspileConfig:
89
89
  return Path(self.transpiler_config_path) if self.transpiler_config_path is not None else None
90
90
 
91
91
  @property
92
- def input_path(self):
92
+ def input_path(self) -> Path:
93
93
  if self.input_source is None:
94
94
  raise ValueError("Missing input source!")
95
95
  return Path(self.input_source)
96
96
 
97
97
  @property
98
- def output_path(self):
98
+ def output_path(self) -> Path | None:
99
99
  return None if self.output_folder is None else Path(self.output_folder)
100
100
 
101
101
  @property
102
- def error_path(self):
102
+ def error_path(self) -> Path | None:
103
103
  return Path(self.error_file_path) if self.error_file_path else None
104
104
 
105
105
  @property
106
- def target_dialect(self):
106
+ def target_dialect(self) -> Literal["databricks"]:
107
107
  return "databricks"
108
108
 
109
109
  @classmethod
110
- def v1_migrate(cls, raw: dict) -> dict:
110
+ def v1_migrate(cls, raw: dict[str, Any]) -> dict[str, Any]:
111
111
  raw["version"] = 2
112
112
  return raw
113
113
 
114
114
  @classmethod
115
- def v2_migrate(cls, raw: dict) -> dict:
115
+ def v2_migrate(cls, raw: dict[str, Any]) -> dict[str, Any]:
116
116
  del raw["mode"]
117
117
  key_mapping = {"input_sql": "input_source", "output_folder": "output_path", "source": "source_dialect"}
118
118
  raw["version"] = 3
@@ -46,7 +46,8 @@ class ReconDeployment:
46
46
  logger.info("Installing reconcile components.")
47
47
  self._deploy_tables(recon_config)
48
48
  self._deploy_dashboards(recon_config)
49
- remorph_wheel_path = [whl for whl in wheel_paths if "remorph" in whl][0]
49
+ # TODO INVESTIGATE: Why is this needed?
50
+ remorph_wheel_path = [whl for whl in wheel_paths if "lakebridge" in whl][0]
50
51
  self._deploy_jobs(recon_config, remorph_wheel_path)
51
52
  self._install_state.save()
52
53
  logger.info("Installation of reconcile components completed successfully.")
@@ -51,14 +51,3 @@ def get_sql_file(input_path: str | Path) -> Generator[Path, None, None]:
51
51
  for filename in files:
52
52
  if is_sql_file(filename):
53
53
  yield filename
54
-
55
-
56
- def read_file(filename: str | Path) -> str:
57
- """
58
- Reads the contents of the given file and returns it as a string.
59
- :param filename: Input File Path
60
- :return: File Contents as String
61
- """
62
- # pylint: disable=unspecified-encoding
63
- with Path(filename).open() as file:
64
- return file.read()
@@ -0,0 +1,28 @@
1
+ def refactor_hexadecimal_chars(input_string: str) -> str:
2
+ """
3
+ Updates the HexaDecimal characters ( \x1b[\\d+m ) in the given string as below.
4
+ :param input_string: String with HexaDecimal characters. ex: ( \x1b[4mWHERE\x1b[0m )
5
+ :return: String with HexaDecimal characters refactored to arrows. ex: ( --> WHERE <--)
6
+ """
7
+ output_string = input_string
8
+ highlight = {"\x1b[4m": "--> ", "\x1b[0m": " <--"}
9
+ for key, value in highlight.items():
10
+ output_string = output_string.replace(key, value)
11
+ return output_string
12
+
13
+
14
+ def format_error_message(error_type: str, error_message: Exception, error_sql: str) -> str:
15
+ """
16
+ Formats the error message with the error SQL.
17
+ :param error_type: Error Type
18
+ :param error_message: Error message
19
+ :param error_sql: Error SQL
20
+ :return: Formatted error message
21
+ """
22
+ error_str = (
23
+ f"------------------------ {error_type} Start:------------------------\n"
24
+ f"/*\n{str(error_message)}\n*/\n\n"
25
+ f"/*\nOriginal Query:\n\n{str(error_sql)}\n*/\n"
26
+ f"------------------------- {error_type} End:-------------------------"
27
+ ).strip()
28
+ return error_str
@@ -558,7 +558,7 @@ class WorkspaceInstaller:
558
558
  @classmethod
559
559
  def install_morpheus(cls, artifact: Path | None = None):
560
560
  java_version = cls.get_java_version()
561
- if java_version is None or java_version < 110:
561
+ if java_version is None or java_version < (11, 0, 0, 0):
562
562
  logger.warning(
563
563
  "This software requires Java 11 or above. Please install Java and re-run 'install-transpile'."
564
564
  )
@@ -582,25 +582,48 @@ class WorkspaceInstaller:
582
582
  logger.fatal(f"Cannot install unsupported artifact: {artifact}")
583
583
 
584
584
  @classmethod
585
- def get_java_version(cls) -> int | None:
586
- completed = run(["java", "-version"], shell=False, capture_output=True, check=False)
587
- try:
588
- completed.check_returncode()
589
- except CalledProcessError:
590
- return None
591
- result = completed.stderr.decode("utf-8")
592
- start = result.find(" version ")
593
- if start < 0:
585
+ def get_java_version(cls) -> tuple[int, int, int, int] | None:
586
+ # Platform-independent way to reliably locate the java executable.
587
+ # Reference: https://docs.python.org/3.10/library/subprocess.html#popen-constructor
588
+ java_executable = shutil.which("java")
589
+ if java_executable is None:
594
590
  return None
595
- start = result.find('"', start + 1)
596
- if start < 0:
591
+ try:
592
+ completed = run([java_executable, "-version"], shell=False, capture_output=True, check=True)
593
+ except CalledProcessError as e:
594
+ logger.debug(
595
+ f"Failed to run {e.args!r} (exit-code={e.returncode}, stdout={e.stdout!r}, stderr={e.stderr!r})",
596
+ exc_info=e,
597
+ )
597
598
  return None
598
- end = result.find('"', start + 1)
599
- if end < 0:
599
+ # It might not be ascii, but the bits we care about are so this will never fail.
600
+ java_version_output = completed.stderr.decode("ascii", errors="ignore")
601
+ java_version = cls._parse_java_version(java_version_output)
602
+ logger.debug(f"Detected java version: {java_version}")
603
+ return java_version
604
+
605
+ # Pattern to match a Java version string, compiled at import time to ensure it's valid.
606
+ # Ref: https://docs.oracle.com/en/java/javase/11/install/version-string-format.html
607
+ _java_version_pattern = re.compile(
608
+ r' version "(?P<feature>\d+)(?:\.(?P<interim>\d+)(?:\.(?P<update>\d+)(?:\.(?P<patch>\d+))?)?)?"'
609
+ )
610
+
611
+ @classmethod
612
+ def _parse_java_version(cls, version: str) -> tuple[int, int, int, int] | None:
613
+ """Locate and parse the Java version in the output of `java -version`."""
614
+ # Output looks like this:
615
+ # openjdk version "24.0.1" 2025-04-15
616
+ # OpenJDK Runtime Environment Temurin-24.0.1+9 (build 24.0.1+9)
617
+ # OpenJDK 64-Bit Server VM Temurin-24.0.1+9 (build 24.0.1+9, mixed mode)
618
+ match = cls._java_version_pattern.search(version)
619
+ if not match:
620
+ logger.debug(f"Could not parse java version: {version!r}")
600
621
  return None
601
- version = result[start + 1 : end]
602
- parts = version.split('.')
603
- return int(parts[0] + parts[1])
622
+ feature = int(match["feature"])
623
+ interim = int(match["interim"] or 0)
624
+ update = int(match["update"] or 0)
625
+ patch = int(match["patch"] or 0)
626
+ return feature, interim, update, patch
604
627
 
605
628
  def configure(self, module: str) -> RemorphConfigs:
606
629
  match module:
@@ -624,10 +647,10 @@ class WorkspaceInstaller:
624
647
 
625
648
  def _configure_transpile(self) -> TranspileConfig:
626
649
  try:
627
- self._installation.load(TranspileConfig)
650
+ config = self._installation.load(TranspileConfig)
628
651
  logger.info("Lakebridge `transpile` is already installed on this workspace.")
629
652
  if not self._prompts.confirm("Do you want to override the existing installation?"):
630
- raise SystemExit("Lak `transpile` is already installed and no override has been requested. Exiting...")
653
+ return config
631
654
  except NotFound:
632
655
  logger.info("Couldn't find existing `transpile` installation")
633
656
  except (PermissionDenied, SerdeError, ValueError, AttributeError):
@@ -689,8 +712,7 @@ class WorkspaceInstaller:
689
712
  transpiler_name = None
690
713
  else:
691
714
  transpiler_name = next(t for t in transpilers)
692
- # TODO Change name for bladebridge
693
- logger.info(f"lakebridge will use the {transpiler_name} transpiler")
715
+ logger.info(f"Lakebridge will use the {transpiler_name} transpiler")
694
716
  if transpiler_name:
695
717
  transpiler_config_path = self._transpiler_config_path(transpiler_name)
696
718
  transpiler_options: dict[str, JsonValue] | None = None
@@ -749,10 +771,11 @@ class WorkspaceInstaller:
749
771
  def _configure_reconcile(self) -> ReconcileConfig:
750
772
  try:
751
773
  self._installation.load(ReconcileConfig)
752
- logger.info("lakebridge `reconcile` is already installed on this workspace.")
774
+ logger.info("Lakebridge `reconcile` is already installed on this workspace.")
753
775
  if not self._prompts.confirm("Do you want to override the existing installation?"):
776
+ # TODO: Exit gracefully, without raising SystemExit
754
777
  raise SystemExit(
755
- "lakebridge `reconcile` is already installed and no override has been requested. Exiting..."
778
+ "Lakebridge `reconcile` is already installed and no override has been requested. Exiting..."
756
779
  )
757
780
  except NotFound:
758
781
  logger.info("Couldn't find existing `reconcile` installation")
@@ -1,11 +1,9 @@
1
1
  import logging
2
2
  from pathlib import Path
3
3
 
4
- from databricks.labs.lakebridge.helpers.file_utils import (
5
- get_sql_file,
6
- is_sql_file,
7
- read_file,
8
- )
4
+ from databricks.labs.blueprint.paths import read_text
5
+
6
+ from databricks.labs.lakebridge.helpers.file_utils import get_sql_file, is_sql_file
9
7
  from databricks.labs.lakebridge.intermediate.dag import DAG
10
8
 
11
9
  from databricks.labs.lakebridge.transpiler.sqlglot.sqlglot_engine import SqlglotEngine
@@ -26,14 +24,14 @@ class RootTableAnalyzer:
26
24
  # when input is sql file then parse the file
27
25
  if is_sql_file(self.input_path):
28
26
  logger.debug(f"Generating Lineage file: {self.input_path}")
29
- sql_content = read_file(self.input_path)
27
+ sql_content = read_text(self.input_path)
30
28
  self._populate_dag(sql_content, self.input_path, dag)
31
29
  return dag # return after processing the file
32
30
 
33
31
  # when the input is a directory
34
32
  for path in get_sql_file(self.input_path):
35
33
  logger.debug(f"Generating Lineage file: {path}")
36
- sql_content = read_file(path)
34
+ sql_content = read_text(path)
37
35
  self._populate_dag(sql_content, path, dag)
38
36
 
39
37
  return dag
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import dataclasses
3
3
  import logging
4
- import math
4
+ from email import policy
5
5
  from email.message import Message
6
6
  from email.parser import Parser as EmailParser
7
7
  from pathlib import Path
@@ -9,6 +9,7 @@ from typing import cast
9
9
  import itertools
10
10
 
11
11
  from databricks.labs.blueprint.installation import JsonObject
12
+ from databricks.labs.blueprint.paths import read_text
12
13
  from databricks.labs.lakebridge.__about__ import __version__
13
14
  from databricks.labs.lakebridge.config import (
14
15
  TranspileConfig,
@@ -28,7 +29,6 @@ from databricks.labs.lakebridge.transpiler.transpile_status import (
28
29
  ErrorKind,
29
30
  ErrorSeverity,
30
31
  )
31
- from databricks.labs.lakebridge.helpers.string_utils import remove_bom
32
32
  from databricks.labs.lakebridge.helpers.validation import Validator
33
33
  from databricks.labs.lakebridge.transpiler.sqlglot.sqlglot_engine import SqlglotEngine
34
34
  from databricks.sdk import WorkspaceClient
@@ -62,15 +62,14 @@ async def _process_one_file(context: TranspilingContext) -> tuple[int, list[Tran
62
62
  )
63
63
  return 0, [error]
64
64
 
65
- with context.input_path.open("r") as f:
66
- source_code = remove_bom(f.read())
67
- context = dataclasses.replace(context, source_code=source_code)
65
+ source_code = read_text(context.input_path)
66
+ context = dataclasses.replace(context, source_code=source_code)
68
67
 
69
68
  transpile_result = await _transpile(
70
69
  context.transpiler,
71
70
  str(context.config.source_dialect),
72
71
  context.config.target_dialect,
73
- str(context.source_code),
72
+ source_code,
74
73
  context.input_path,
75
74
  )
76
75
 
@@ -98,7 +97,8 @@ def _is_combined_result(result: TranspileResult):
98
97
 
99
98
  def _process_combined_result(context: TranspilingContext, _error_list: list[TranspileError]) -> None:
100
99
  # TODO error handling
101
- parser = EmailParser()
100
+ # Added policy to process quoted-printable encoded
101
+ parser = EmailParser(policy=policy.default)
102
102
  transpiled_code: str = cast(str, context.transpiled_code)
103
103
  message: Message = parser.parsestr(transpiled_code)
104
104
  for part in message.walk():
@@ -107,18 +107,27 @@ def _process_combined_result(context: TranspilingContext, _error_list: list[Tran
107
107
 
108
108
  def _process_combined_part(context: TranspilingContext, part: Message) -> None:
109
109
  if part.get_content_type() != "text/plain":
110
- return
110
+ return # TODO Need to handle other content types, e.g., text/binary, application/json, etc.
111
111
  filename = part.get_filename()
112
- content = part.get_payload(decode=False)
113
- if not filename or not isinstance(content, str):
114
- return
112
+ payload = part.get_payload(decode=True)
113
+ charset = part.get_content_charset() or "utf-8"
114
+ if isinstance(payload, bytes):
115
+ content = payload.decode(charset)
116
+ else:
117
+ content = str(payload)
118
+ logger.debug(f"Processing file: {filename}")
119
+
120
+ if not filename:
121
+ return # TODO Raise exception!!!!
122
+ filename = Path(filename).name
115
123
  folder = context.output_folder
116
124
  segments = filename.split("/")
117
125
  for segment in segments[:-1]:
118
126
  folder = folder / segment
119
127
  folder.mkdir(parents=True, exist_ok=True)
120
128
  output = folder / segments[-1]
121
- output.write_text(content, "utf-8")
129
+ logger.debug(f"Writing output to: {output}")
130
+ output.write_text(content)
122
131
 
123
132
 
124
133
  def _process_single_result(context: TranspilingContext, error_list: list[TranspileError]) -> None:
@@ -128,14 +137,6 @@ def _process_single_result(context: TranspilingContext, error_list: list[Transpi
128
137
  if any(err.kind == ErrorKind.PARSING for err in error_list):
129
138
  output_code = context.source_code or ""
130
139
 
131
- if error_list:
132
- with_line_numbers = ""
133
- lines = output_code.split("\n")
134
- line_number_width = math.floor(math.log(len(lines), 10)) + 1
135
- for line_number, line in enumerate(lines, start=1):
136
- with_line_numbers += f"/* {line_number:{line_number_width}d} */ {line}\n"
137
- output_code = with_line_numbers
138
-
139
140
  elif context.validator:
140
141
  logger.debug(f"Validating transpiled code for file: {context.input_path}")
141
142
  validation_result = _validation(context.validator, context.config, str(context.transpiled_code))
@@ -156,38 +157,35 @@ def _process_single_result(context: TranspilingContext, error_list: list[Transpi
156
157
 
157
158
  output_path = cast(Path, context.output_path)
158
159
  with output_path.open("w") as w:
159
- w.write(_make_header(context.input_path, error_list))
160
+ # The above adds a java-style comment block at the top of the output file
161
+ # This would break .py or .json outputs so we disable it for now.
162
+ # w.write(make_header(context.input_path, error_list))
160
163
  w.write(output_code)
161
164
 
162
165
  logger.info(f"Processed file: {context.input_path} (errors: {len(error_list)})")
163
166
 
164
167
 
165
- def _make_header(file_path: Path, errors: list[TranspileError]) -> str:
168
+ def make_header(file_path: Path, errors: list[TranspileError]) -> str:
166
169
  header = ""
167
170
  failed_producing_output = False
168
- diag_by_severity = {}
169
- line_numbers = {}
170
-
171
- for severity, diags in itertools.groupby(errors, key=lambda x: x.severity):
172
- diag_by_severity[severity] = list(diags)
171
+ diag_by_severity = {
172
+ severity.name: list(diags) for severity, diags in itertools.groupby(errors, key=lambda x: x.severity)
173
+ }
174
+ line_numbers: dict[int, int] = {}
173
175
 
174
- if ErrorSeverity.ERROR in diag_by_severity:
176
+ if ErrorSeverity.ERROR.name in diag_by_severity:
175
177
  header += f"/*\n Failed transpilation of {file_path}\n"
176
178
  header += "\n The following errors were found while transpiling:\n"
177
- for diag in diag_by_severity[ErrorSeverity.ERROR]:
178
- if diag.range:
179
- line_numbers[diag.range.start.line] = 0
180
- header += _append_diagnostic(diag)
181
- failed_producing_output = failed_producing_output or diag.kind == ErrorKind.PARSING
179
+ header += _append_diagnostics(diag_by_severity[ErrorSeverity.ERROR.name], line_numbers)
180
+ failed_producing_output = failed_producing_output or any(
181
+ x.kind == ErrorKind.PARSING for x in diag_by_severity[ErrorSeverity.ERROR.name]
182
+ )
182
183
  else:
183
184
  header += f"/*\n Successfully transpiled from {file_path}\n"
184
185
 
185
- if ErrorSeverity.WARNING in diag_by_severity:
186
+ if ErrorSeverity.WARNING.name in diag_by_severity:
186
187
  header += "\n The following warnings were found while transpiling:\n"
187
- for diag in diag_by_severity[ErrorSeverity.WARNING]:
188
- if diag.range:
189
- line_numbers[diag.range.start.line] = 0
190
- header += _append_diagnostic(diag)
188
+ header += _append_diagnostics(diag_by_severity[ErrorSeverity.WARNING.name], line_numbers)
191
189
 
192
190
  if failed_producing_output:
193
191
  header += "\n\n Parsing errors prevented the converter from translating the input query.\n"
@@ -203,13 +201,29 @@ def _make_header(file_path: Path, errors: list[TranspileError]) -> str:
203
201
  return header.format(line_numbers=line_numbers)
204
202
 
205
203
 
206
- def _append_diagnostic(diag: TranspileError) -> str:
207
- message = diag.message.replace("{", "{{").replace("}", "}}")
208
- if diag.range:
209
- line = diag.range.start.line
210
- column = diag.range.start.character + 1
211
- return f" - [{{line_numbers[{line}]}}:{column}] {message}\n"
212
- return f" - {message}\n"
204
+ def _append_diagnostics(diagnostics: list[TranspileError], line_numbers: dict) -> str:
205
+ header = ""
206
+ grouped_by_message = {msg: list(diags) for msg, diags in itertools.groupby(diagnostics, lambda x: x.message)}
207
+ for msg, occurrences in grouped_by_message.items():
208
+ for occurrence in occurrences:
209
+ if occurrence.range:
210
+ line_numbers.update({occurrence.range.start.line: 0})
211
+ header += _append_diagnostic(msg, occurrences)
212
+ return header
213
+
214
+
215
+ def _append_diagnostic(msg: str, diags: list[TranspileError]) -> str:
216
+ positions = [
217
+ f"[{{line_numbers[{diag.range.start.line}]}}:{diag.range.start.character + 1}]" for diag in diags if diag.range
218
+ ]
219
+ message = msg.replace("{", "{{").replace("}", "}}").replace("/n", "\n ")
220
+ result = f" - {message}\n" if len(positions) != 1 else f" - {positions[0]} {message}\n"
221
+ if len(positions) > 1:
222
+ positions_str = ", ".join(positions)
223
+ result += f" Occurred {len(diags)} times at the following positions: {positions_str}\n"
224
+ elif len(diags) > 1:
225
+ result += f" Occurred {len(diags)} times\n"
226
+ return result
213
227
 
214
228
 
215
229
  async def _process_many_files(
@@ -330,7 +344,7 @@ async def _do_transpile(
330
344
  msg = f"{config.input_source} does not exist."
331
345
  logger.error(msg)
332
346
  raise FileNotFoundError(msg)
333
- logger.info(f"Transpiler results: {result}")
347
+ logger.debug(f"Transpiler results: {result}")
334
348
 
335
349
  if not config.skip_validation:
336
350
  logger.info(f"SQL validation errors: {result.validation_error_count}")
@@ -523,9 +523,7 @@ class LSPEngine(TranspileEngine):
523
523
  self.close_document(file_path)
524
524
  return ChangeManager.apply(source_code, response.changes, response.diagnostics, file_path)
525
525
 
526
- def open_document(self, file_path: Path, encoding="utf-8", source_code: str | None = None) -> None:
527
- if source_code is None:
528
- source_code = file_path.read_text(encoding)
526
+ def open_document(self, file_path: Path, source_code: str) -> None:
529
527
  text_document = TextDocumentItem(
530
528
  uri=file_path.as_uri(), language_id=LanguageKind.Sql, version=1, text=source_code
531
529
  )
@@ -21,7 +21,7 @@ if __name__ == "__main__":
21
21
  run(
22
22
  ApplicationContext(
23
23
  WorkspaceClient(
24
- product="remorph",
24
+ product="lakebridge",
25
25
  product_version=__version__,
26
26
  )
27
27
  )
@@ -0,0 +1,42 @@
1
+ import React, {memo, type ReactNode} from 'react';
2
+ import {useLocation, useHistory} from 'react-router';
3
+ import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
4
+ import {
5
+ DocSidebarItemsExpandedStateProvider,
6
+ useVisibleSidebarItems,
7
+ } from '@docusaurus/plugin-content-docs/client';
8
+ import DocSidebarItem from '@theme/DocSidebarItem';
9
+
10
+ import type {Props} from '@theme/DocSidebarItems';
11
+
12
+ function DocSidebarItems({items, onItemClick, ...props}: Props): ReactNode {
13
+ const location = useLocation();
14
+ const history = useHistory();
15
+ const visibleItems = useVisibleSidebarItems(items, props.activePath);
16
+
17
+ /**
18
+ * Additional logic for handling custom UI scenarios
19
+ */
20
+ const onClickHandler = (params: PropSidebarItem) => {
21
+ if (onItemClick) {
22
+ onItemClick(params);
23
+ }
24
+
25
+ // show initial page on menu collapse
26
+ if (params.type === "category") {
27
+ if (location.pathname !== params.href && location.pathname.includes(params.href)) {
28
+ history.push(params.href);
29
+ }
30
+ }
31
+ }
32
+
33
+ return (
34
+ <DocSidebarItemsExpandedStateProvider>
35
+ {visibleItems.map((item, index) => (
36
+ <DocSidebarItem key={index} item={item} index={index} {...props} onItemClick={onClickHandler} />
37
+ ))}
38
+ </DocSidebarItemsExpandedStateProvider>
39
+ );
40
+ }
41
+
42
+ export default memo(DocSidebarItems);