semantic-link-labs 0.9.11__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of semantic-link-labs might be problematic. Click here for more details.

Files changed (209) hide show
  1. {semantic_link_labs-0.9.11/src/semantic_link_labs.egg-info → semantic_link_labs-0.10.0}/PKG-INFO +3 -2
  2. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/README.md +2 -1
  3. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/pyproject.toml +1 -1
  4. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0/src/semantic_link_labs.egg-info}/PKG-INFO +3 -2
  5. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/semantic_link_labs.egg-info/SOURCES.txt +2 -0
  6. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/__init__.py +4 -0
  7. semantic_link_labs-0.10.0/src/sempy_labs/_dictionary_diffs.py +221 -0
  8. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_helper_functions.py +165 -0
  9. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_sql.py +1 -1
  10. semantic_link_labs-0.10.0/src/sempy_labs/_user_delegation_key.py +42 -0
  11. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_vpax.py +2 -0
  12. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/__init__.py +0 -2
  13. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_blobs.py +0 -37
  14. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/__init__.py +2 -0
  15. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_helper.py +27 -128
  16. semantic_link_labs-0.10.0/src/sempy_labs/report/_reportwrapper.py +2949 -0
  17. semantic_link_labs-0.9.11/src/sempy_labs/report/_reportwrapper.py +0 -2224
  18. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/LICENSE +0 -0
  19. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/setup.cfg +0 -0
  20. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/semantic_link_labs.egg-info/dependency_links.txt +0 -0
  21. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/semantic_link_labs.egg-info/requires.txt +0 -0
  22. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/semantic_link_labs.egg-info/top_level.txt +0 -0
  23. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_ai.py +0 -0
  24. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_authentication.py +0 -0
  25. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_am-ET.po +0 -0
  26. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ar-AE.po +0 -0
  27. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +0 -0
  28. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +0 -0
  29. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_cs-CZ.po +0 -0
  30. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_da-DK.po +0 -0
  31. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_de-DE.po +0 -0
  32. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_el-GR.po +0 -0
  33. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_es-ES.po +0 -0
  34. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_fa-IR.po +0 -0
  35. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +0 -0
  36. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_fr-FR.po +0 -0
  37. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ga-IE.po +0 -0
  38. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_he-IL.po +0 -0
  39. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_hi-IN.po +0 -0
  40. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_hu-HU.po +0 -0
  41. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_id-ID.po +0 -0
  42. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_is-IS.po +0 -0
  43. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_it-IT.po +0 -0
  44. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ja-JP.po +0 -0
  45. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +0 -0
  46. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +0 -0
  47. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_nl-NL.po +0 -0
  48. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_pl-PL.po +0 -0
  49. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_pt-BR.po +0 -0
  50. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_pt-PT.po +0 -0
  51. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +0 -0
  52. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ru-RU.po +0 -0
  53. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +0 -0
  54. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +0 -0
  55. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_sv-SE.po +0 -0
  56. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_ta-IN.po +0 -0
  57. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_te-IN.po +0 -0
  58. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_th-TH.po +0 -0
  59. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +0 -0
  60. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +0 -0
  61. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_zh-CN.po +0 -0
  62. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_bpa_translation/_model/_translations_zu-ZA.po +0 -0
  63. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_capacities.py +0 -0
  64. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_capacity_migration.py +0 -0
  65. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_clear_cache.py +0 -0
  66. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_connections.py +0 -0
  67. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_dashboards.py +0 -0
  68. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_data_pipelines.py +0 -0
  69. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_dataflows.py +0 -0
  70. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_dax.py +0 -0
  71. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_dax_query_view.py +0 -0
  72. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_delta_analyzer.py +0 -0
  73. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_delta_analyzer_history.py +0 -0
  74. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_deployment_pipelines.py +0 -0
  75. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_documentation.py +0 -0
  76. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_environments.py +0 -0
  77. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_eventhouses.py +0 -0
  78. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_eventstreams.py +0 -0
  79. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_external_data_shares.py +0 -0
  80. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_gateways.py +0 -0
  81. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_generate_semantic_model.py +0 -0
  82. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_git.py +0 -0
  83. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_graphQL.py +0 -0
  84. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_icons.py +0 -0
  85. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_job_scheduler.py +0 -0
  86. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_kql_databases.py +0 -0
  87. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_kql_querysets.py +0 -0
  88. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_kusto.py +0 -0
  89. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_list_functions.py +0 -0
  90. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_managed_private_endpoints.py +0 -0
  91. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_mirrored_databases.py +0 -0
  92. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_mirrored_warehouses.py +0 -0
  93. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_ml_experiments.py +0 -0
  94. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_ml_models.py +0 -0
  95. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_model_auto_build.py +0 -0
  96. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_model_bpa.py +0 -0
  97. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_model_bpa_bulk.py +0 -0
  98. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_model_bpa_rules.py +0 -0
  99. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_model_dependencies.py +0 -0
  100. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_mounted_data_factories.py +0 -0
  101. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_notebooks.py +0 -0
  102. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_one_lake_integration.py +0 -0
  103. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_query_scale_out.py +0 -0
  104. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_refresh_semantic_model.py +0 -0
  105. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_semantic_models.py +0 -0
  106. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_spark.py +0 -0
  107. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_sqldatabase.py +0 -0
  108. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_tags.py +0 -0
  109. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_translations.py +0 -0
  110. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_utils.py +0 -0
  111. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_variable_libraries.py +0 -0
  112. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_vertipaq.py +0 -0
  113. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_warehouses.py +0 -0
  114. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_workloads.py +0 -0
  115. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_workspace_identity.py +0 -0
  116. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/_workspaces.py +0 -0
  117. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/__init__.py +0 -0
  118. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_activities.py +0 -0
  119. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_apps.py +0 -0
  120. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_artifacts.py +0 -0
  121. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_basic_functions.py +0 -0
  122. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_capacities.py +0 -0
  123. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_dataflows.py +0 -0
  124. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_datasets.py +0 -0
  125. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_domains.py +0 -0
  126. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_external_data_share.py +0 -0
  127. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_git.py +0 -0
  128. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_items.py +0 -0
  129. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_reports.py +0 -0
  130. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_scanner.py +0 -0
  131. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_shared.py +0 -0
  132. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_tags.py +0 -0
  133. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_tenant.py +0 -0
  134. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_users.py +0 -0
  135. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/admin/_workspaces.py +0 -0
  136. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/__init__.py +0 -0
  137. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_directlake_schema_compare.py +0 -0
  138. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_directlake_schema_sync.py +0 -0
  139. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_dl_helper.py +0 -0
  140. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_generate_shared_expression.py +0 -0
  141. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_get_directlake_lakehouse.py +0 -0
  142. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_get_shared_expression.py +0 -0
  143. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_guardrails.py +0 -0
  144. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_list_directlake_model_calc_tables.py +0 -0
  145. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_show_unsupported_directlake_objects.py +0 -0
  146. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +0 -0
  147. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_update_directlake_partition_entity.py +0 -0
  148. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/directlake/_warm_cache.py +0 -0
  149. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/dotnet_lib/dotnet.runtime.config.json +0 -0
  150. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/graph/__init__.py +0 -0
  151. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/graph/_groups.py +0 -0
  152. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/graph/_teams.py +0 -0
  153. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/graph/_users.py +0 -0
  154. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_get_lakehouse_columns.py +0 -0
  155. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_get_lakehouse_tables.py +0 -0
  156. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_helper.py +0 -0
  157. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_lakehouse.py +0 -0
  158. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_livy_sessions.py +0 -0
  159. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/lakehouse/_shortcuts.py +0 -0
  160. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/__init__.py +0 -0
  161. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_create_pqt_file.py +0 -0
  162. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_direct_lake_to_import.py +0 -0
  163. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_migrate_calctables_to_lakehouse.py +0 -0
  164. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_migrate_calctables_to_semantic_model.py +0 -0
  165. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +0 -0
  166. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +0 -0
  167. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_migration_validation.py +0 -0
  168. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/migration/_refresh_calc_tables.py +0 -0
  169. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_BPAReportTemplate.json +0 -0
  170. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/StaticResources/SharedResources/BaseThemes/CY24SU06.json +0 -0
  171. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/page.json +0 -0
  172. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/1b08bce3bebabb0a27a8/visual.json +0 -0
  173. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/2f22ddb70c301693c165/visual.json +0 -0
  174. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/3b1182230aa6c600b43a/visual.json +0 -0
  175. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/58577ba6380c69891500/visual.json +0 -0
  176. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/a2a8fa5028b3b776c96c/visual.json +0 -0
  177. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/adfd47ef30652707b987/visual.json +0 -0
  178. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/b6a80ee459e716e170b1/visual.json +0 -0
  179. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/01d72098bda5055bd500/visuals/ce3130a721c020cc3d81/visual.json +0 -0
  180. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/page.json +0 -0
  181. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/92735ae19b31712208ad/visuals/66e60dfb526437cd78d1/visual.json +0 -0
  182. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/page.json +0 -0
  183. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/07deb8bce824e1be37d7/visual.json +0 -0
  184. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0b1c68838818b32ad03b/visual.json +0 -0
  185. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0c171de9d2683d10b930/visual.json +0 -0
  186. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/0efa01be0510e40a645e/visual.json +0 -0
  187. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/6bf2f0eb830ab53cc668/visual.json +0 -0
  188. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/88d8141cb8500b60030c/visual.json +0 -0
  189. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/a753273590beed656a03/visual.json +0 -0
  190. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/c597da16dc7e63222a82/visuals/b8fdc82cddd61ac447bc/visual.json +0 -0
  191. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/page.json +0 -0
  192. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/d37dce724a0ccc30044b/visuals/ce8532a7e25020271077/visual.json +0 -0
  193. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/pages/pages.json +0 -0
  194. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/report.json +0 -0
  195. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition/version.json +0 -0
  196. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_bpareporttemplate/definition.pbir +0 -0
  197. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_download_report.py +0 -0
  198. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_export_report.py +0 -0
  199. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_generate_report.py +0 -0
  200. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_paginated.py +0 -0
  201. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_bpa.py +0 -0
  202. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_bpa_rules.py +0 -0
  203. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_functions.py +0 -0
  204. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_list_functions.py +0 -0
  205. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_report_rebind.py +0 -0
  206. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/report/_save_report.py +0 -0
  207. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/tom/__init__.py +0 -0
  208. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/src/sempy_labs/tom/_model.py +0 -0
  209. {semantic_link_labs-0.9.11 → semantic_link_labs-0.10.0}/tests/test_friendly_case.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: semantic-link-labs
3
- Version: 0.9.11
3
+ Version: 0.10.0
4
4
  Summary: Semantic Link Labs for Microsoft Fabric
5
5
  Author: Microsoft Corporation
6
6
  License: MIT License
@@ -27,7 +27,7 @@ Dynamic: license-file
27
27
  # Semantic Link Labs
28
28
 
29
29
  [![PyPI version](https://badge.fury.io/py/semantic-link-labs.svg)](https://badge.fury.io/py/semantic-link-labs)
30
- [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.9.11&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
30
+ [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.10.0&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
31
31
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
32
32
  [![Downloads](https://static.pepy.tech/badge/semantic-link-labs)](https://pepy.tech/project/semantic-link-labs)
33
33
 
@@ -154,6 +154,7 @@ An even better way to ensure the semantic-link-labs library is available in your
154
154
  2. Select your newly created environment within the 'Environment' drop down in the navigation bar at the top of the notebook
155
155
 
156
156
  ## Version History
157
+ * [0.10.0](https://github.com/microsoft/semantic-link-labs/releases/tag/0.10.0) (May 30, 2025)
157
158
  * [0.9.11](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.11) (May 22, 2025)
158
159
  * [0.9.10](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.10) (April 24, 2025)
159
160
  * [0.9.9](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.9) (April 7, 2025)
@@ -1,7 +1,7 @@
1
1
  # Semantic Link Labs
2
2
 
3
3
  [![PyPI version](https://badge.fury.io/py/semantic-link-labs.svg)](https://badge.fury.io/py/semantic-link-labs)
4
- [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.9.11&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
4
+ [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.10.0&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
5
5
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
6
6
  [![Downloads](https://static.pepy.tech/badge/semantic-link-labs)](https://pepy.tech/project/semantic-link-labs)
7
7
 
@@ -128,6 +128,7 @@ An even better way to ensure the semantic-link-labs library is available in your
128
128
  2. Select your newly created environment within the 'Environment' drop down in the navigation bar at the top of the notebook
129
129
 
130
130
  ## Version History
131
+ * [0.10.0](https://github.com/microsoft/semantic-link-labs/releases/tag/0.10.0) (May 30, 2025)
131
132
  * [0.9.11](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.11) (May 22, 2025)
132
133
  * [0.9.10](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.10) (April 24, 2025)
133
134
  * [0.9.9](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.9) (April 7, 2025)
@@ -7,7 +7,7 @@ name="semantic-link-labs"
7
7
  authors = [
8
8
  { name = "Microsoft Corporation" },
9
9
  ]
10
- version="0.9.11"
10
+ version="0.10.0"
11
11
  description="Semantic Link Labs for Microsoft Fabric"
12
12
  readme="README.md"
13
13
  requires-python=">=3.10,<3.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: semantic-link-labs
3
- Version: 0.9.11
3
+ Version: 0.10.0
4
4
  Summary: Semantic Link Labs for Microsoft Fabric
5
5
  Author: Microsoft Corporation
6
6
  License: MIT License
@@ -27,7 +27,7 @@ Dynamic: license-file
27
27
  # Semantic Link Labs
28
28
 
29
29
  [![PyPI version](https://badge.fury.io/py/semantic-link-labs.svg)](https://badge.fury.io/py/semantic-link-labs)
30
- [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.9.11&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
30
+ [![Read The Docs](https://readthedocs.org/projects/semantic-link-labs/badge/?version=0.10.0&style=flat)](https://readthedocs.org/projects/semantic-link-labs/)
31
31
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
32
32
  [![Downloads](https://static.pepy.tech/badge/semantic-link-labs)](https://pepy.tech/project/semantic-link-labs)
33
33
 
@@ -154,6 +154,7 @@ An even better way to ensure the semantic-link-labs library is available in your
154
154
  2. Select your newly created environment within the 'Environment' drop down in the navigation bar at the top of the notebook
155
155
 
156
156
  ## Version History
157
+ * [0.10.0](https://github.com/microsoft/semantic-link-labs/releases/tag/0.10.0) (May 30, 2025)
157
158
  * [0.9.11](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.11) (May 22, 2025)
158
159
  * [0.9.10](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.10) (April 24, 2025)
159
160
  * [0.9.9](https://github.com/microsoft/semantic-link-labs/releases/tag/0.9.9) (April 7, 2025)
@@ -21,6 +21,7 @@ src/sempy_labs/_dax_query_view.py
21
21
  src/sempy_labs/_delta_analyzer.py
22
22
  src/sempy_labs/_delta_analyzer_history.py
23
23
  src/sempy_labs/_deployment_pipelines.py
24
+ src/sempy_labs/_dictionary_diffs.py
24
25
  src/sempy_labs/_documentation.py
25
26
  src/sempy_labs/_environments.py
26
27
  src/sempy_labs/_eventhouses.py
@@ -58,6 +59,7 @@ src/sempy_labs/_sql.py
58
59
  src/sempy_labs/_sqldatabase.py
59
60
  src/sempy_labs/_tags.py
60
61
  src/sempy_labs/_translations.py
62
+ src/sempy_labs/_user_delegation_key.py
61
63
  src/sempy_labs/_utils.py
62
64
  src/sempy_labs/_variable_libraries.py
63
65
  src/sempy_labs/_vertipaq.py
@@ -340,6 +340,9 @@ from sempy_labs._vertipaq import (
340
340
  vertipaq_analyzer,
341
341
  import_vertipaq_analyzer,
342
342
  )
343
+ from sempy_labs._user_delegation_key import (
344
+ get_user_delegation_key,
345
+ )
343
346
 
344
347
  __all__ = [
345
348
  "resolve_warehouse_id",
@@ -585,4 +588,5 @@ __all__ = [
585
588
  "update_semantic_model_refresh_schedule",
586
589
  "apply_tags",
587
590
  "unapply_tags",
591
+ "get_user_delegation_key",
588
592
  ]
@@ -0,0 +1,221 @@
1
+ import re
2
+ import json
3
+ import difflib
4
+ from collections import defaultdict
5
+
6
+
7
+ def color_text(text, color_code):
8
+ return f"\033[{color_code}m{text}\033[0m"
9
+
10
+
11
+ def stringify(payload):
12
+ try:
13
+ if isinstance(payload, list):
14
+ return (
15
+ "[\n" + ",\n".join(f" {json.dumps(item)}" for item in payload) + "\n]"
16
+ )
17
+ return json.dumps(payload, indent=2, sort_keys=True)
18
+ except Exception:
19
+ return str(payload)
20
+
21
+
22
+ def extract_top_level_group(path):
23
+ # For something like: resourcePackages[1].items[1].name → resourcePackages[1].items[1]
24
+ segments = re.split(r"\.(?![^[]*\])", path) # split on dots not in brackets
25
+ return ".".join(segments[:-1]) if len(segments) > 1 else segments[0]
26
+
27
+
28
+ def get_by_path(obj, path):
29
+ """Navigate into nested dict/list based on a dot/bracket path like: a.b[1].c"""
30
+ tokens = re.findall(r"\w+|\[\d+\]", path)
31
+ for token in tokens:
32
+ if token.startswith("["):
33
+ index = int(token[1:-1])
34
+ obj = obj[index]
35
+ else:
36
+ obj = obj.get(token)
37
+ return obj
38
+
39
+
40
+ def deep_diff(d1, d2, path=""):
41
+ diffs = []
42
+ if isinstance(d1, dict) and isinstance(d2, dict):
43
+ keys = set(d1) | set(d2)
44
+ for key in sorted(keys):
45
+ new_path = f"{path}.{key}" if path else key
46
+ if key not in d1:
47
+ diffs.append(("+", new_path, None, d2[key]))
48
+ elif key not in d2:
49
+ diffs.append(("-", new_path, d1[key], None))
50
+ else:
51
+ diffs.extend(deep_diff(d1[key], d2[key], new_path))
52
+ elif isinstance(d1, list) and isinstance(d2, list):
53
+ min_len = min(len(d1), len(d2))
54
+ list_changed = False
55
+ for i in range(min_len):
56
+ if d1[i] != d2[i]:
57
+ list_changed = True
58
+ break
59
+ if list_changed or len(d1) != len(d2):
60
+ diffs.append(("~", path, d1, d2))
61
+ elif d1 != d2:
62
+ diffs.append(("~", path, d1, d2))
63
+ return diffs
64
+
65
+
66
+ def diff_parts(d1, d2):
67
+
68
+ def build_path_map(parts):
69
+ return {part["path"]: part["payload"] for part in parts}
70
+
71
+ try:
72
+ paths1 = build_path_map(d1)
73
+ except Exception:
74
+ paths1 = d1
75
+ try:
76
+ paths2 = build_path_map(d2)
77
+ except Exception:
78
+ paths2 = d2
79
+ all_paths = set(paths1) | set(paths2)
80
+
81
+ for part_path in sorted(all_paths):
82
+ p1 = paths1.get(part_path)
83
+ p2 = paths2.get(part_path)
84
+
85
+ if p1 is None:
86
+ print(color_text(f"+ {part_path}", "32")) # Green
87
+ continue
88
+ elif p2 is None:
89
+ print(color_text(f"- {part_path}", "31")) # Red
90
+ continue
91
+ elif p1 == p2:
92
+ continue
93
+
94
+ if p1 is None or p2 is None:
95
+ print(
96
+ color_text(f"+ {part_path}", "32")
97
+ if p2 and not p1
98
+ else color_text(f"- {part_path}", "31")
99
+ )
100
+ continue
101
+
102
+ # Header for the changed part
103
+ print(color_text(f"~ {part_path}", "33"))
104
+
105
+ # Collect diffs
106
+ diffs = deep_diff(p1, p2)
107
+ # If the diff is only a change of a whole list (like appending to a list), group it under its key
108
+ merged_list_diffs = []
109
+ for change_type, full_path, old_val, new_val in diffs:
110
+ if (
111
+ change_type == "~"
112
+ and isinstance(old_val, list)
113
+ and isinstance(new_val, list)
114
+ ):
115
+ merged_list_diffs.append((change_type, full_path, old_val, new_val))
116
+
117
+ # Replace individual item diffs with unified list diff
118
+ if merged_list_diffs:
119
+ diffs = merged_list_diffs
120
+
121
+ # Group diffs by common parent path (e.g. items[1])
122
+ grouped = defaultdict(list)
123
+ for change_type, full_path, old_val, new_val in diffs:
124
+ group_path = extract_top_level_group(full_path)
125
+ grouped[group_path].append((change_type, full_path, old_val, new_val))
126
+
127
+ # Print each group once with unified diff for the full substructure
128
+ for group_path in sorted(grouped):
129
+ print(" " + color_text(f"~ {group_path}", "33"))
130
+
131
+ try:
132
+ old_group = get_by_path(p1, group_path)
133
+ new_group = get_by_path(p2, group_path)
134
+ except Exception:
135
+ old_group = new_group = None
136
+
137
+ # Skip showing diffs for empty/null groups
138
+ if isinstance(old_group, dict) and isinstance(new_group, dict):
139
+ old_keys = set(old_group.keys())
140
+ new_keys = set(new_group.keys())
141
+
142
+ for key in sorted(old_keys - new_keys):
143
+ print(
144
+ " "
145
+ + color_text(f"- {key}: {json.dumps(old_group[key])}", "31")
146
+ )
147
+ for key in sorted(new_keys - old_keys):
148
+ print(
149
+ " "
150
+ + color_text(f"+ {key}: {json.dumps(new_group[key])}", "32")
151
+ )
152
+ for key in sorted(old_keys & new_keys):
153
+ if old_group[key] != new_group[key]:
154
+ print(" " + color_text(f"~ {key}:", "33"))
155
+ old_val_str = stringify(old_group[key]).splitlines()
156
+ new_val_str = stringify(new_group[key]).splitlines()
157
+ for line in difflib.unified_diff(
158
+ old_val_str,
159
+ new_val_str,
160
+ fromfile="old",
161
+ tofile="new",
162
+ lineterm="",
163
+ ):
164
+ if line.startswith("@@"):
165
+ print(" " + color_text(line, "36"))
166
+ elif line.startswith("-") and not line.startswith("---"):
167
+ print(" " + color_text(line, "31"))
168
+ elif line.startswith("+") and not line.startswith("+++"):
169
+ print(" " + color_text(line, "32"))
170
+ elif old_group is None and new_group is not None:
171
+ if isinstance(new_group, dict):
172
+ # print all added keys
173
+ for key, val in new_group.items():
174
+ print(" " + color_text(f"+ {key}: {json.dumps(val)}", "32"))
175
+ elif isinstance(new_group, list):
176
+ old_str = []
177
+ new_str = stringify(new_group).splitlines()
178
+ for line in difflib.unified_diff(
179
+ old_str, new_str, fromfile="old", tofile="new", lineterm=""
180
+ ):
181
+ if line.startswith("@@"):
182
+ print(" " + color_text(line, "36"))
183
+ elif line.startswith("-") and not line.startswith("---"):
184
+ print(" " + color_text(line, "31"))
185
+ elif line.startswith("+") and not line.startswith("+++"):
186
+ print(" " + color_text(line, "32"))
187
+ else:
188
+ print(" " + color_text(f"+ {json.dumps(new_group)}", "32"))
189
+
190
+ elif new_group is None and old_group is not None:
191
+ if isinstance(old_group, dict):
192
+ # print all removed keys
193
+ for key, val in old_group.items():
194
+ print(" " + color_text(f"- {key}: {json.dumps(val)}", "31"))
195
+ elif isinstance(old_group, list):
196
+ old_str = stringify(old_group).splitlines()
197
+ new_str = []
198
+ for line in difflib.unified_diff(
199
+ old_str, new_str, fromfile="old", tofile="new", lineterm=""
200
+ ):
201
+ if line.startswith("@@"):
202
+ print(" " + color_text(line, "36"))
203
+ elif line.startswith("-") and not line.startswith("---"):
204
+ print(" " + color_text(line, "31"))
205
+ elif line.startswith("+") and not line.startswith("+++"):
206
+ print(" " + color_text(line, "32"))
207
+ else:
208
+ print(" " + color_text(f"- {json.dumps(old_group)}", "31"))
209
+ else:
210
+ old_str = stringify(old_group).splitlines()
211
+ new_str = stringify(new_group).splitlines()
212
+
213
+ for line in difflib.unified_diff(
214
+ old_str, new_str, fromfile="old", tofile="new", lineterm=""
215
+ ):
216
+ if line.startswith("@@"):
217
+ print(" " + color_text(line, "36"))
218
+ elif line.startswith("-") and not line.startswith("---"):
219
+ print(" " + color_text(line, "31"))
220
+ elif line.startswith("+") and not line.startswith("+++"):
221
+ print(" " + color_text(line, "32"))
@@ -17,6 +17,8 @@ import numpy as np
17
17
  from IPython.display import display, HTML
18
18
  import requests
19
19
  import sempy_labs._authentication as auth
20
+ from jsonpath_ng.ext import parse
21
+ from jsonpath_ng.jsonpath import Fields, Index
20
22
 
21
23
 
22
24
  def _build_url(url: str, params: dict) -> str:
@@ -2270,3 +2272,166 @@ def file_exists(file_path: str) -> bool:
2270
2272
  import notebookutils
2271
2273
 
2272
2274
  return len(notebookutils.fs.ls(file_path)) > 0
2275
+
2276
+
2277
+ def generate_number_guid():
2278
+
2279
+ guid = uuid.uuid4()
2280
+ return str(guid.int & ((1 << 64) - 1))
2281
+
2282
+
2283
+ def get_url_content(url: str):
2284
+
2285
+ if "github.com" in url and "/blob/" in url:
2286
+ url = url.replace("github.com", "raw.githubusercontent.com")
2287
+ url = url.replace("/blob/", "/")
2288
+
2289
+ response = requests.get(url)
2290
+ if response.ok:
2291
+ try:
2292
+ data = response.json() # Only works if the response is valid JSON
2293
+ except ValueError:
2294
+ data = response.text # Fallback: get raw text content
2295
+ return data
2296
+ else:
2297
+ print(f"Failed to fetch raw content: {response.status_code}")
2298
+
2299
+
2300
+ def generate_hex(length: int = 10) -> str:
2301
+ """
2302
+ Generate a random hex string of the specified length. Used for generating IDs for report objects (page, visual, bookmark etc.).
2303
+ """
2304
+ import secrets
2305
+
2306
+ return secrets.token_hex(length)
2307
+
2308
+
2309
+ def decode_payload(payload):
2310
+
2311
+ if is_base64(payload):
2312
+ try:
2313
+ decoded_payload = json.loads(base64.b64decode(payload).decode("utf-8"))
2314
+ except Exception:
2315
+ decoded_payload = base64.b64decode(payload)
2316
+ elif isinstance(payload, dict):
2317
+ decoded_payload = payload
2318
+ else:
2319
+ raise ValueError("Payload must be a dictionary or a base64 encoded value.")
2320
+
2321
+ return decoded_payload
2322
+
2323
+
2324
+ def is_base64(s):
2325
+ try:
2326
+ # Add padding if needed
2327
+ s_padded = s + "=" * (-len(s) % 4)
2328
+ decoded = base64.b64decode(s_padded, validate=True)
2329
+ # Optional: check if re-encoding gives the original (excluding padding)
2330
+ return base64.b64encode(decoded).decode().rstrip("=") == s.rstrip("=")
2331
+ except Exception:
2332
+ return False
2333
+
2334
+
2335
+ def get_jsonpath_value(
2336
+ data, path, default=None, remove_quotes=False, fix_true: bool = False
2337
+ ):
2338
+ matches = parse(path).find(data)
2339
+ result = matches[0].value if matches else default
2340
+ if result and remove_quotes and isinstance(result, str):
2341
+ if result.startswith("'") and result.endswith("'"):
2342
+ result = result[1:-1]
2343
+ if fix_true and isinstance(result, str):
2344
+ if result.lower() == "true":
2345
+ result = True
2346
+ elif result.lower() == "false":
2347
+ result = False
2348
+ return result
2349
+
2350
+
2351
+ def set_json_value(payload: dict, json_path: str, json_value: str | dict | List):
2352
+
2353
+ jsonpath_expr = parse(json_path)
2354
+ matches = jsonpath_expr.find(payload)
2355
+
2356
+ if matches:
2357
+ # Update all matches
2358
+ for match in matches:
2359
+ parent = match.context.value
2360
+ path = match.path
2361
+ if isinstance(path, Fields):
2362
+ parent[path.fields[0]] = json_value
2363
+ elif isinstance(path, Index):
2364
+ parent[path.index] = json_value
2365
+ else:
2366
+ # Handle creation
2367
+ parts = json_path.lstrip("$").strip(".").split(".")
2368
+ current = payload
2369
+
2370
+ for i, part in enumerate(parts):
2371
+ is_last = i == len(parts) - 1
2372
+
2373
+ # Detect list syntax like "lockAspect[*]"
2374
+ list_match = re.match(r"(\w+)\[\*\]", part)
2375
+ if list_match:
2376
+ list_key = list_match.group(1)
2377
+ if list_key not in current or not isinstance(current[list_key], list):
2378
+ # Initialize with one dict element
2379
+ current[list_key] = [{}]
2380
+
2381
+ for item in current[list_key]:
2382
+ if is_last:
2383
+ # Last part, assign value
2384
+ item = json_value
2385
+ else:
2386
+ # Proceed to next level
2387
+ if not isinstance(item, dict):
2388
+ raise ValueError(
2389
+ f"Expected dict in list for key '{list_key}', got {type(item)}"
2390
+ )
2391
+ next_part = ".".join(parts[i + 1 :])
2392
+ set_json_value(item, "$." + next_part, json_value)
2393
+ return payload
2394
+ else:
2395
+ if part not in current or not isinstance(current[part], dict):
2396
+ current[part] = {} if not is_last else json_value
2397
+ elif is_last:
2398
+ current[part] = json_value
2399
+ current = current[part]
2400
+
2401
+ return payload
2402
+
2403
+
2404
+ def remove_json_value(path: str, payload: dict, json_path: str, verbose: bool = True):
2405
+
2406
+ if not isinstance(payload, dict):
2407
+ raise ValueError(
2408
+ f"{icons.red_dot} Cannot apply json_path to non-dictionary payload in '{path}'."
2409
+ )
2410
+
2411
+ jsonpath_expr = parse(json_path)
2412
+ matches = jsonpath_expr.find(payload)
2413
+
2414
+ if not matches and verbose:
2415
+ print(
2416
+ f"{icons.red_dot} No match found for '{json_path}' in '{path}'. Skipping."
2417
+ )
2418
+ return payload
2419
+
2420
+ for match in matches:
2421
+ parent = match.context.value
2422
+ path_expr = match.path
2423
+
2424
+ if isinstance(path_expr, Fields):
2425
+ key = path_expr.fields[0]
2426
+ if key in parent:
2427
+ del parent[key]
2428
+ if verbose:
2429
+ print(f"{icons.green_dot} Removed key '{key}' from '{path}'.")
2430
+ elif isinstance(path_expr, Index):
2431
+ index = path_expr.index
2432
+ if isinstance(parent, list) and 0 <= index < len(parent):
2433
+ parent.pop(index)
2434
+ if verbose:
2435
+ print(f"{icons.green_dot} Removed index [{index}] from '{path}'.")
2436
+
2437
+ return payload
@@ -82,7 +82,7 @@ class ConnectBase:
82
82
  )
83
83
 
84
84
  # Set up the connection string
85
- access_token = SynapseTokenProvider()()
85
+ access_token = SynapseTokenProvider()("sql")
86
86
  tokenstruct = _bytes2mswin_bstr(access_token.encode())
87
87
  if endpoint_type == "sqldatabase":
88
88
  conn_str = f"DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={tds_endpoint};DATABASE={resource_name}-{resource_id};Encrypt=Yes;"
@@ -0,0 +1,42 @@
1
+ from sempy_labs.lakehouse._blobs import _request_blob_api
2
+ from sempy_labs._helper_functions import (
3
+ _xml_to_dict,
4
+ )
5
+ from datetime import datetime, timedelta, timezone
6
+ import xml.etree.ElementTree as ET
7
+
8
+
9
+ def get_user_delegation_key():
10
+ """
11
+ Gets a key that can be used to sign a user delegation SAS (shared access signature). A user delegation SAS grants access to Azure Blob Storage resources by using Microsoft Entra credentials.
12
+
13
+ This is a wrapper function for the following API: `Get User Delegation Key <https://learn.microsoft.com/rest/api/storageservices/get-user-delegation-key>`_.
14
+
15
+ Returns
16
+ -------
17
+ str
18
+ The user delegation key value.
19
+ """
20
+
21
+ utc_now = datetime.now(timezone.utc)
22
+ start_time = utc_now + timedelta(minutes=2)
23
+ expiry_time = start_time + timedelta(minutes=60)
24
+ start_str = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
25
+ expiry_str = expiry_time.strftime("%Y-%m-%dT%H:%M:%SZ")
26
+
27
+ payload = f"""<?xml version="1.0" encoding="utf-8"?>
28
+ <KeyInfo>
29
+ <Start>{start_str}</Start>
30
+ <Expiry>{expiry_str}</Expiry>
31
+ </KeyInfo>"""
32
+
33
+ response = _request_blob_api(
34
+ request="?restype=service&comp=userdelegationkey",
35
+ method="post",
36
+ payload=payload,
37
+ )
38
+
39
+ root = ET.fromstring(response.content)
40
+ response_json = _xml_to_dict(root)
41
+
42
+ return response_json.get("UserDelegationKey", {}).get("Value", None)
@@ -16,6 +16,7 @@ from sempy_labs._helper_functions import (
16
16
  file_exists,
17
17
  create_abfss_path_from_path,
18
18
  )
19
+ from sempy._utils._log import log
19
20
  import sempy_labs._icons as icons
20
21
  import zipfile
21
22
  import requests
@@ -134,6 +135,7 @@ def init_vertipaq_analyzer():
134
135
  _vpa_initialized = True
135
136
 
136
137
 
138
+ @log
137
139
  def create_vpax(
138
140
  dataset: str | UUID,
139
141
  workspace: Optional[str | UUID] = None,
@@ -20,7 +20,6 @@ from sempy_labs.lakehouse._shortcuts import (
20
20
  from sempy_labs.lakehouse._blobs import (
21
21
  recover_lakehouse_object,
22
22
  list_blobs,
23
- get_user_delegation_key,
24
23
  )
25
24
  from sempy_labs.lakehouse._livy_sessions import (
26
25
  list_livy_sessions,
@@ -51,5 +50,4 @@ __all__ = [
51
50
  "delete_lakehouse",
52
51
  "update_lakehouse",
53
52
  "load_table",
54
- "get_user_delegation_key",
55
53
  ]
@@ -244,40 +244,3 @@ def recover_lakehouse_object(
244
244
  print(
245
245
  f"{icons.red_dot} An error occurred while recovering the '{blob_name}' blob: {e}"
246
246
  )
247
-
248
-
249
- def get_user_delegation_key():
250
- """
251
- Gets a key that can be used to sign a user delegation SAS (shared access signature). A user delegation SAS grants access to Azure Blob Storage resources by using Microsoft Entra credentials.
252
-
253
- This is a wrapper function for the following API: `Get User Delegation Key <https://learn.microsoft.com/rest/api/storageservices/get-user-delegation-key>`_.
254
-
255
- Returns
256
- -------
257
- str
258
- The user delegation key value.
259
- """
260
-
261
- from datetime import datetime, timedelta, timezone
262
-
263
- utc_now = datetime.now(timezone.utc)
264
- start_time = utc_now + timedelta(minutes=2)
265
- expiry_time = start_time + timedelta(minutes=60)
266
- start_str = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
267
- expiry_str = expiry_time.strftime("%Y-%m-%dT%H:%M:%SZ")
268
-
269
- payload = f"""<?xml version="1.0" encoding="utf-8"?>
270
- <KeyInfo>
271
- <Start>{start_str}</Start>
272
- <Expiry>{expiry_str}</Expiry>
273
- </KeyInfo>"""
274
-
275
- response = _request_blob_api(
276
- request="?restype=service&comp=userdelegationkey",
277
- method="post",
278
- payload=payload,
279
- )
280
-
281
- root = ET.fromstring(response.content)
282
- response_json = _xml_to_dict(root)
283
- return response_json.get("UserDelegationKey", {}).get("Value", None)
@@ -3,6 +3,7 @@ from sempy_labs.report._save_report import (
3
3
  )
4
4
  from sempy_labs.report._reportwrapper import (
5
5
  ReportWrapper,
6
+ connect_report,
6
7
  )
7
8
  from sempy_labs.report._paginated import (
8
9
  get_report_datasources,
@@ -50,4 +51,5 @@ __all__ = [
50
51
  "get_report_datasources",
51
52
  "download_report",
52
53
  "save_report_as_pbip",
54
+ "connect_report",
53
55
  ]