semantic-link-labs 0.8.2__py3-none-any.whl → 0.8.4__py3-none-any.whl

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 (108) hide show
  1. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.4.dist-info}/METADATA +37 -8
  2. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.4.dist-info}/RECORD +108 -104
  3. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.4.dist-info}/WHEEL +1 -1
  4. sempy_labs/__init__.py +38 -0
  5. sempy_labs/_bpa_translation/_model/_translations_am-ET.po +24 -5
  6. sempy_labs/_bpa_translation/_model/_translations_ar-AE.po +28 -4
  7. sempy_labs/_bpa_translation/_model/_translations_bg-BG.po +34 -4
  8. sempy_labs/_bpa_translation/_model/_translations_ca-ES.po +33 -4
  9. sempy_labs/_bpa_translation/_model/_translations_cs-CZ.po +31 -4
  10. sempy_labs/_bpa_translation/_model/_translations_da-DK.po +31 -4
  11. sempy_labs/_bpa_translation/_model/_translations_de-DE.po +34 -4
  12. sempy_labs/_bpa_translation/_model/_translations_el-GR.po +36 -4
  13. sempy_labs/_bpa_translation/_model/_translations_es-ES.po +90 -58
  14. sempy_labs/_bpa_translation/_model/_translations_fa-IR.po +31 -5
  15. sempy_labs/_bpa_translation/_model/_translations_fi-FI.po +31 -4
  16. sempy_labs/_bpa_translation/_model/_translations_fr-FR.po +34 -4
  17. sempy_labs/_bpa_translation/_model/_translations_ga-IE.po +34 -4
  18. sempy_labs/_bpa_translation/_model/_translations_he-IL.po +28 -4
  19. sempy_labs/_bpa_translation/_model/_translations_hi-IN.po +32 -4
  20. sempy_labs/_bpa_translation/_model/_translations_hu-HU.po +32 -4
  21. sempy_labs/_bpa_translation/_model/_translations_id-ID.po +32 -4
  22. sempy_labs/_bpa_translation/_model/_translations_is-IS.po +31 -4
  23. sempy_labs/_bpa_translation/_model/_translations_it-IT.po +34 -4
  24. sempy_labs/_bpa_translation/_model/_translations_ja-JP.po +24 -4
  25. sempy_labs/_bpa_translation/_model/_translations_ko-KR.po +72 -56
  26. sempy_labs/_bpa_translation/_model/_translations_mt-MT.po +34 -4
  27. sempy_labs/_bpa_translation/_model/_translations_nl-NL.po +34 -4
  28. sempy_labs/_bpa_translation/_model/_translations_pl-PL.po +95 -71
  29. sempy_labs/_bpa_translation/_model/_translations_pt-BR.po +32 -4
  30. sempy_labs/_bpa_translation/_model/_translations_pt-PT.po +32 -4
  31. sempy_labs/_bpa_translation/_model/_translations_ro-RO.po +33 -4
  32. sempy_labs/_bpa_translation/_model/_translations_ru-RU.po +34 -4
  33. sempy_labs/_bpa_translation/_model/_translations_sk-SK.po +31 -4
  34. sempy_labs/_bpa_translation/_model/_translations_sl-SL.po +32 -4
  35. sempy_labs/_bpa_translation/_model/_translations_sv-SE.po +32 -4
  36. sempy_labs/_bpa_translation/_model/_translations_ta-IN.po +32 -4
  37. sempy_labs/_bpa_translation/_model/_translations_te-IN.po +31 -4
  38. sempy_labs/_bpa_translation/_model/_translations_th-TH.po +31 -4
  39. sempy_labs/_bpa_translation/_model/_translations_tr-TR.po +32 -4
  40. sempy_labs/_bpa_translation/_model/_translations_uk-UA.po +100 -72
  41. sempy_labs/_bpa_translation/_model/_translations_zh-CN.po +23 -5
  42. sempy_labs/_bpa_translation/_model/_translations_zu-ZA.po +32 -4
  43. sempy_labs/_capacities.py +138 -25
  44. sempy_labs/_capacity_migration.py +161 -60
  45. sempy_labs/_clear_cache.py +3 -3
  46. sempy_labs/_data_pipelines.py +54 -0
  47. sempy_labs/_dataflows.py +4 -0
  48. sempy_labs/_deployment_pipelines.py +13 -7
  49. sempy_labs/_environments.py +6 -0
  50. sempy_labs/_eventhouses.py +6 -0
  51. sempy_labs/_eventstreams.py +6 -0
  52. sempy_labs/_external_data_shares.py +190 -0
  53. sempy_labs/_generate_semantic_model.py +26 -4
  54. sempy_labs/_git.py +15 -15
  55. sempy_labs/_helper_functions.py +186 -11
  56. sempy_labs/_icons.py +55 -22
  57. sempy_labs/_kql_databases.py +6 -0
  58. sempy_labs/_kql_querysets.py +6 -0
  59. sempy_labs/_list_functions.py +6 -3
  60. sempy_labs/_managed_private_endpoints.py +166 -0
  61. sempy_labs/_mirrored_warehouses.py +2 -0
  62. sempy_labs/_ml_experiments.py +6 -0
  63. sempy_labs/_ml_models.py +6 -0
  64. sempy_labs/_model_bpa.py +11 -6
  65. sempy_labs/_model_bpa_bulk.py +14 -30
  66. sempy_labs/_model_bpa_rules.py +8 -3
  67. sempy_labs/_notebooks.py +111 -15
  68. sempy_labs/_query_scale_out.py +8 -6
  69. sempy_labs/_refresh_semantic_model.py +299 -49
  70. sempy_labs/_spark.py +12 -5
  71. sempy_labs/_sql.py +2 -2
  72. sempy_labs/_translations.py +16 -14
  73. sempy_labs/_vertipaq.py +127 -116
  74. sempy_labs/_warehouses.py +90 -1
  75. sempy_labs/_workloads.py +128 -0
  76. sempy_labs/_workspace_identity.py +4 -4
  77. sempy_labs/_workspaces.py +14 -1
  78. sempy_labs/admin/__init__.py +2 -0
  79. sempy_labs/admin/_basic_functions.py +203 -58
  80. sempy_labs/admin/_domains.py +18 -18
  81. sempy_labs/directlake/__init__.py +2 -0
  82. sempy_labs/directlake/_directlake_schema_sync.py +2 -6
  83. sempy_labs/directlake/_dl_helper.py +4 -1
  84. sempy_labs/directlake/_generate_shared_expression.py +1 -1
  85. sempy_labs/directlake/_get_shared_expression.py +7 -1
  86. sempy_labs/directlake/_guardrails.py +3 -2
  87. sempy_labs/directlake/_show_unsupported_directlake_objects.py +2 -8
  88. sempy_labs/directlake/_update_directlake_model_lakehouse_connection.py +78 -0
  89. sempy_labs/directlake/_update_directlake_partition_entity.py +13 -32
  90. sempy_labs/lakehouse/_get_lakehouse_tables.py +6 -2
  91. sempy_labs/lakehouse/_shortcuts.py +4 -0
  92. sempy_labs/migration/_create_pqt_file.py +2 -2
  93. sempy_labs/migration/_migrate_calctables_to_lakehouse.py +3 -2
  94. sempy_labs/migration/_migrate_calctables_to_semantic_model.py +2 -0
  95. sempy_labs/migration/_migrate_model_objects_to_semantic_model.py +2 -8
  96. sempy_labs/migration/_migrate_tables_columns_to_semantic_model.py +17 -0
  97. sempy_labs/migration/_migration_validation.py +2 -0
  98. sempy_labs/migration/_refresh_calc_tables.py +1 -0
  99. sempy_labs/report/__init__.py +4 -1
  100. sempy_labs/report/_generate_report.py +16 -14
  101. sempy_labs/report/_paginated.py +74 -0
  102. sempy_labs/report/_report_bpa.py +8 -10
  103. sempy_labs/report/_report_functions.py +19 -19
  104. sempy_labs/report/_report_rebind.py +6 -1
  105. sempy_labs/report/_reportwrapper.py +3 -3
  106. sempy_labs/tom/_model.py +173 -67
  107. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.4.dist-info}/LICENSE +0 -0
  108. {semantic_link_labs-0.8.2.dist-info → semantic_link_labs-0.8.4.dist-info}/top_level.txt +0 -0
sempy_labs/_capacities.py CHANGED
@@ -4,7 +4,7 @@ from sempy._utils._log import log
4
4
  import sempy_labs._icons as icons
5
5
  from sempy.fabric.exceptions import FabricHTTPException
6
6
  import requests
7
- from sempy_labs._helper_functions import get_azure_token_credentials
7
+ from sempy_labs._helper_functions import _get_azure_token_credentials
8
8
  import pandas as pd
9
9
 
10
10
 
@@ -37,6 +37,8 @@ def create_fabric_capacity(
37
37
  """
38
38
  This function creates a new Fabric capacity within an Azure subscription.
39
39
 
40
+ This is a wrapper function for the following API: `Fabric Capacities - Create Or Update <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/create-or-update?view=rest-microsoftfabric-2023-11-01>`_.
41
+
40
42
  Parameters
41
43
  ----------
42
44
  capacity_name : str
@@ -65,8 +67,6 @@ def create_fabric_capacity(
65
67
 
66
68
  from azure.mgmt.resource import ResourceManagementClient
67
69
 
68
- capacity_suffix = "fsku"
69
-
70
70
  if isinstance(admin_members, str):
71
71
  admin_members = [admin_members]
72
72
 
@@ -143,7 +143,7 @@ def create_fabric_capacity(
143
143
  f"{icons.red_dot} Invalid region. Valid options: {valid_regions}."
144
144
  )
145
145
 
146
- azure_token, credential, headers = get_azure_token_credentials(
146
+ azure_token, credential, headers = _get_azure_token_credentials(
147
147
  key_vault_uri=key_vault_uri,
148
148
  key_vault_tenant_id=key_vault_tenant_id,
149
149
  key_vault_client_id=key_vault_client_id,
@@ -255,6 +255,8 @@ def suspend_fabric_capacity(
255
255
  """
256
256
  This function suspends a Fabric capacity.
257
257
 
258
+ This is a wrapper function for the following API: `Fabric Capacities - Suspend <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/suspend?view=rest-microsoftfabric-2023-11-01>`_.
259
+
258
260
  Parameters
259
261
  ----------
260
262
  capacity_name : str
@@ -274,7 +276,7 @@ def suspend_fabric_capacity(
274
276
  """
275
277
  # https://learn.microsoft.com/en-us/rest/api/microsoftfabric/fabric-capacities/suspend?view=rest-microsoftfabric-2023-11-01&tabs=HTTP
276
278
 
277
- azure_token, credential, headers = get_azure_token_credentials(
279
+ azure_token, credential, headers = _get_azure_token_credentials(
278
280
  key_vault_uri=key_vault_uri,
279
281
  key_vault_tenant_id=key_vault_tenant_id,
280
282
  key_vault_client_id=key_vault_client_id,
@@ -288,7 +290,7 @@ def suspend_fabric_capacity(
288
290
  if response.status_code != 202:
289
291
  raise FabricHTTPException(response)
290
292
 
291
- print(f"{icons.green_dot} The '{capacity_name} capacity has been suspended.")
293
+ print(f"{icons.green_dot} The '{capacity_name}' capacity has been suspended.")
292
294
 
293
295
 
294
296
  def resume_fabric_capacity(
@@ -303,6 +305,8 @@ def resume_fabric_capacity(
303
305
  """
304
306
  This function resumes a Fabric capacity.
305
307
 
308
+ This is a wrapper function for the following API: `Fabric Capacities - Resume <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/resume?view=rest-microsoftfabric-2023-11-01>`_.
309
+
306
310
  Parameters
307
311
  ----------
308
312
  capacity_name : str
@@ -323,7 +327,7 @@ def resume_fabric_capacity(
323
327
 
324
328
  # https://learn.microsoft.com/en-us/rest/api/microsoftfabric/fabric-capacities/resume?view=rest-microsoftfabric-2023-11-01&tabs=HTTP
325
329
 
326
- azure_token, credential, headers = get_azure_token_credentials(
330
+ azure_token, credential, headers = _get_azure_token_credentials(
327
331
  key_vault_uri=key_vault_uri,
328
332
  key_vault_tenant_id=key_vault_tenant_id,
329
333
  key_vault_client_id=key_vault_client_id,
@@ -337,7 +341,7 @@ def resume_fabric_capacity(
337
341
  if response.status_code != 202:
338
342
  raise FabricHTTPException(response)
339
343
 
340
- print(f"{icons.green_dot} The '{capacity_name} capacity has been resumed.")
344
+ print(f"{icons.green_dot} The '{capacity_name}' capacity has been resumed.")
341
345
 
342
346
 
343
347
  def delete_embedded_capacity(
@@ -372,7 +376,7 @@ def delete_embedded_capacity(
372
376
 
373
377
  # https://learn.microsoft.com/en-us/rest/api/power-bi-embedded/capacities/delete?view=rest-power-bi-embedded-2021-01-01&tabs=HTTP
374
378
 
375
- azure_token, credential, headers = get_azure_token_credentials(
379
+ azure_token, credential, headers = _get_azure_token_credentials(
376
380
  key_vault_uri=key_vault_uri,
377
381
  key_vault_tenant_id=key_vault_tenant_id,
378
382
  key_vault_client_id=key_vault_client_id,
@@ -386,7 +390,7 @@ def delete_embedded_capacity(
386
390
  if response.status_code not in [200, 202]:
387
391
  raise FabricHTTPException(response)
388
392
 
389
- print(f"{icons.green_dot} The '{capacity_name} capacity has been deleted.")
393
+ print(f"{icons.green_dot} The '{capacity_name}' capacity has been deleted.")
390
394
 
391
395
 
392
396
  def delete_premium_capacity(capacity_name: str):
@@ -429,6 +433,8 @@ def delete_fabric_capacity(
429
433
  """
430
434
  This function deletes a Fabric capacity.
431
435
 
436
+ This is a wrapper function for the following API: `Fabric Capacities - Delete <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/delete?view=rest-microsoftfabric-2023-11-01>`_.
437
+
432
438
  Parameters
433
439
  ----------
434
440
  capacity_name : str
@@ -449,7 +455,7 @@ def delete_fabric_capacity(
449
455
 
450
456
  # https://learn.microsoft.com/en-us/rest/api/microsoftfabric/fabric-capacities/delete?view=rest-microsoftfabric-2023-11-01&tabs=HTTP
451
457
 
452
- azure_token, credential, headers = get_azure_token_credentials(
458
+ azure_token, credential, headers = _get_azure_token_credentials(
453
459
  key_vault_uri=key_vault_uri,
454
460
  key_vault_tenant_id=key_vault_tenant_id,
455
461
  key_vault_client_id=key_vault_client_id,
@@ -463,7 +469,7 @@ def delete_fabric_capacity(
463
469
  if response.status_code != 202:
464
470
  raise FabricHTTPException(response)
465
471
 
466
- print(f"{icons.green_dot} The '{capacity_name} capacity has been deleted.")
472
+ print(f"{icons.green_dot} The '{capacity_name}' capacity has been deleted.")
467
473
 
468
474
 
469
475
  def update_fabric_capacity(
@@ -481,6 +487,8 @@ def update_fabric_capacity(
481
487
  """
482
488
  This function updates a Fabric capacity's properties.
483
489
 
490
+ This is a wrapper function for the following API: `Fabric Capacities - Update <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/update?view=rest-microsoftfabric-2023-11-01>`_.
491
+
484
492
  Parameters
485
493
  ----------
486
494
  capacity_name : str
@@ -503,7 +511,6 @@ def update_fabric_capacity(
503
511
  The email address(es) of the admin(s) of the Fabric capacity.
504
512
  tags : dict, default=None
505
513
  Tag(s) to add to the capacity. Example: {'tagName': 'tagValue'}.
506
-
507
514
  """
508
515
 
509
516
  # https://learn.microsoft.com/en-us/rest/api/microsoftfabric/fabric-capacities/update?view=rest-microsoftfabric-2023-11-01&tabs=HTTP
@@ -515,7 +522,7 @@ def update_fabric_capacity(
515
522
  f"{icons.red_dot} If specified, the 'tags' parameter must be a dictionary."
516
523
  )
517
524
 
518
- azure_token, credential, headers = get_azure_token_credentials(
525
+ azure_token, credential, headers = _get_azure_token_credentials(
519
526
  key_vault_uri=key_vault_uri,
520
527
  key_vault_tenant_id=key_vault_tenant_id,
521
528
  key_vault_client_id=key_vault_client_id,
@@ -524,26 +531,47 @@ def update_fabric_capacity(
524
531
 
525
532
  url = f"https://management.azure.com/subscriptions/{azure_subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Fabric/capacities/{capacity_name}?api-version={icons.azure_api_version}"
526
533
 
534
+ get_response = requests.get(url, headers=headers)
535
+ if get_response.status_code != 200:
536
+ raise FabricHTTPException(get_response)
537
+
538
+ get_json = get_response.json()
539
+ current_sku = get_json.get("sku", {}).get("name")
540
+ current_admins = (
541
+ get_json.get("properties", {}).get("administration", {}).get("members")
542
+ )
543
+ current_tags = get_json.get("tags")
544
+
527
545
  payload = {}
546
+ payload["sku"] = {
547
+ "name": current_sku,
548
+ "tier": "Fabric",
549
+ }
550
+ payload["tags"] = current_tags
551
+ payload["properties"] = get_json["properties"]
552
+
528
553
  if sku is not None:
529
- payload["sku"] = {"name": sku, "tier": "Fabric"}
554
+ payload["sku"]["name"] = sku
530
555
  if admin_members is not None:
531
- payload["properties"] = {"administration": {"members": [admin_members]}}
532
-
533
- payload = _add_sll_tag(payload, tags)
534
-
535
- if payload == {}:
536
- raise ValueError(
537
- f"{icons.warning} No parameters have been set to update the '{capacity_name}' capacity."
556
+ payload["properties"] = {"administration": {"members": admin_members}}
557
+ if tags is not None:
558
+ payload["tags"] = tags
559
+
560
+ # Do not proceed if no properties are being changed
561
+ if current_sku == sku and current_admins == admin_members and current_tags == tags:
562
+ print(
563
+ f"{icons.yellow_dot} The properties of the '{capacity_name}' are the same as those specified in the parameters of this function. No changes have been made."
538
564
  )
565
+ return
539
566
 
540
- response = requests.patch(url, headers=headers, data=payload)
567
+ payload = _add_sll_tag(payload, tags)
568
+ response = requests.patch(url, headers=headers, json=payload)
541
569
 
542
570
  if response.status_code != 202:
543
571
  raise FabricHTTPException(response)
544
572
 
545
573
  print(
546
- f"{icons.green_dot} The '{capacity_name} capacity has been updated accordingly."
574
+ f"{icons.green_dot} The '{capacity_name}' capacity has been updated accordingly."
547
575
  )
548
576
 
549
577
 
@@ -556,9 +584,36 @@ def check_fabric_capacity_name_availablility(
556
584
  key_vault_client_id: str,
557
585
  key_vault_client_secret: str,
558
586
  ) -> bool:
587
+ """
588
+ This function updates a Fabric capacity's properties.
589
+
590
+ This is a wrapper function for the following API: `Fabric Capacities - Check Name Availability <https://learn.microsoft.com/rest/api/microsoftfabric/fabric-capacities/check-name-availability?view=rest-microsoftfabric-2023-11-01>`_.
591
+
592
+ Parameters
593
+ ----------
594
+ capacity_name : str
595
+ Name of the Fabric capacity.
596
+ azure_subscription_id : str
597
+ The Azure subscription ID.
598
+ region : str
599
+ The region name.
600
+ key_vault_uri : str
601
+ The name of the `Azure key vault <https://azure.microsoft.com/products/key-vault>`_ URI. Example: "https://<Key Vault Name>.vault.azure.net/"
602
+ key_vault_tenant_id : str
603
+ The name of the Azure key vault secret storing the Tenant ID.
604
+ key_vault_client_id : str
605
+ The name of the Azure key vault secret storing the Client ID.
606
+ key_vault_client_secret : str
607
+ The name of the Azure key vault secret storing the Client Secret.
608
+
609
+ Returns
610
+ -------
611
+ bool
612
+ An indication as to whether the Fabric capacity name is available or not.
613
+ """
559
614
  # https://learn.microsoft.com/en-us/rest/api/microsoftfabric/fabric-capacities/check-name-availability?view=rest-microsoftfabric-2023-11-01&tabs=HTTP
560
615
 
561
- azure_token, credential, headers = get_azure_token_credentials(
616
+ azure_token, credential, headers = _get_azure_token_credentials(
562
617
  key_vault_uri=key_vault_uri,
563
618
  key_vault_tenant_id=key_vault_tenant_id,
564
619
  key_vault_client_id=key_vault_client_id,
@@ -575,3 +630,61 @@ def check_fabric_capacity_name_availablility(
575
630
  raise FabricHTTPException(response)
576
631
 
577
632
  return bool(response.json().get("nameAvailable"))
633
+
634
+
635
+ def create_resource_group(
636
+ azure_subscription_id: str,
637
+ key_vault_uri: str,
638
+ key_vault_tenant_id: str,
639
+ key_vault_client_id: str,
640
+ key_vault_client_secret: str,
641
+ resource_group: str,
642
+ region: str,
643
+ ):
644
+ """
645
+ This function creates a resource group in a region within an Azure subscription.
646
+
647
+ This is a wrapper function for the following API: `ResourceGroupsOperations Class - CreateOrUpdate <https://learn.microsoft.com/python/api/azure-mgmt-resource/azure.mgmt.resource.resources.v2022_09_01.operations.resourcegroupsoperations?view=azure-python#azure-mgmt-resource-resources-v2022-09-01-operations-resourcegroupsoperations-create-or-update>`_.
648
+
649
+ Parameters
650
+ ----------
651
+ azure_subscription_id : str
652
+ The Azure subscription ID.
653
+ key_vault_uri : str
654
+ The name of the `Azure key vault <https://azure.microsoft.com/products/key-vault>`_ URI. Example: "https://<Key Vault Name>.vault.azure.net/"
655
+ key_vault_tenant_id : str
656
+ The name of the Azure key vault secret storing the Tenant ID.
657
+ key_vault_client_id : str
658
+ The name of the Azure key vault secret storing the Client ID.
659
+ key_vault_client_secret : str
660
+ The name of the Azure key vault secret storing the Client Secret.
661
+ resource_group : str
662
+ The name of the Azure resource group to be created.
663
+ region : str
664
+ The name of the region in which the resource group will be created.
665
+ """
666
+
667
+ from azure.mgmt.resource import ResourceManagementClient
668
+
669
+ azure_token, credential, headers = _get_azure_token_credentials(
670
+ key_vault_uri=key_vault_uri,
671
+ key_vault_tenant_id=key_vault_tenant_id,
672
+ key_vault_client_id=key_vault_client_id,
673
+ key_vault_client_secret=key_vault_client_secret,
674
+ )
675
+
676
+ resource_client = ResourceManagementClient(credential, azure_subscription_id)
677
+
678
+ if resource_client.resource_groups.check_existence(resource_group):
679
+ print(
680
+ f"{icons.info} The '{resource_group}' resource group already exists in the '{region}' region within the '{azure_subscription_id}' Azure subscription."
681
+ )
682
+ return
683
+
684
+ resource_client.resource_groups.create_or_update(
685
+ resource_group, {"location": region}
686
+ )
687
+
688
+ print(
689
+ f"{icons.green_dot} The '{resource_group}' resource group has been created within the '{region}' region within the '{azure_subscription_id}' Azure subscription."
690
+ )
@@ -7,6 +7,7 @@ from sempy_labs._workspaces import assign_workspace_to_capacity
7
7
  from sempy_labs.admin._basic_functions import (
8
8
  assign_workspaces_to_capacity,
9
9
  _list_capacities_meta,
10
+ list_capacities,
10
11
  )
11
12
  from sempy_labs._helper_functions import (
12
13
  resolve_capacity_id,
@@ -15,6 +16,34 @@ from sempy_labs._helper_functions import (
15
16
  from sempy_labs._capacities import create_fabric_capacity
16
17
 
17
18
 
19
+ def migrate_settings(source_capacity: str, target_capacity: str):
20
+
21
+ migrate_capacity_settings(
22
+ source_capacity=source_capacity,
23
+ target_capacity=target_capacity,
24
+ )
25
+ migrate_access_settings(
26
+ source_capacity=source_capacity,
27
+ target_capacity=target_capacity,
28
+ )
29
+ migrate_notification_settings(
30
+ source_capacity=source_capacity,
31
+ target_capacity=target_capacity,
32
+ )
33
+ migrate_spark_settings(
34
+ source_capacity=source_capacity,
35
+ target_capacity=target_capacity,
36
+ )
37
+ migrate_delegated_tenant_settings(
38
+ source_capacity=source_capacity,
39
+ target_capacity=target_capacity,
40
+ )
41
+ migrate_disaster_recovery_settings(
42
+ source_capacity=source_capacity,
43
+ target_capacity=target_capacity,
44
+ )
45
+
46
+
18
47
  @log
19
48
  def migrate_workspaces(
20
49
  source_capacity: str,
@@ -146,8 +175,6 @@ def migrate_capacities(
146
175
  If set to True, only migrates P skus. If set to False, migrates both P and A skus.
147
176
  """
148
177
 
149
- from sempy_labs._list_functions import list_capacities
150
-
151
178
  if isinstance(capacities, str):
152
179
  capacities = [capacities]
153
180
 
@@ -158,7 +185,7 @@ def migrate_capacities(
158
185
  if capacities is None:
159
186
  dfC_filt = dfC.copy()
160
187
  else:
161
- dfC_filt = dfC[dfC["Display Name"].isin(capacities)]
188
+ dfC_filt = dfC[dfC["Capacity Name"].isin(capacities)]
162
189
 
163
190
  if p_sku_only:
164
191
  dfC_filt = dfC_filt[dfC_filt["Sku"].str.startswith("P")]
@@ -177,14 +204,14 @@ def migrate_capacities(
177
204
  return
178
205
 
179
206
  for _, r in dfC_filt.iterrows():
180
- cap_name = r["Display Name"]
207
+ cap_name = r["Capacity Name"]
181
208
  region = r["Region"]
182
209
  sku_size = r["Sku"]
183
210
  admins = r["Admins"]
184
211
  tgt_capacity = f"{convert_to_alphanumeric_lowercase(cap_name)}{icons.migrate_capacity_suffix}"
185
212
 
186
213
  # Check if target capacity exists
187
- dfC_tgt = dfC[dfC["Display Name"] == tgt_capacity]
214
+ dfC_tgt = dfC[dfC["Capacity Name"] == tgt_capacity]
188
215
 
189
216
  if sku_size[:1] == "A" and use_existing_rg_for_A_sku:
190
217
  rg = None
@@ -221,24 +248,7 @@ def migrate_capacities(
221
248
  )
222
249
 
223
250
  # Migrate settings to new capacity
224
- migrate_capacity_settings(
225
- source_capacity=cap_name, target_capacity=tgt_capacity
226
- )
227
- migrate_access_settings(
228
- source_capacity=cap_name, target_capacity=tgt_capacity
229
- )
230
- migrate_notification_settings(
231
- source_capacity=cap_name, target_capacity=tgt_capacity
232
- )
233
- migrate_delegated_tenant_settings(
234
- source_capacity=cap_name, target_capacity=tgt_capacity
235
- )
236
- migrate_disaster_recovery_settings(
237
- source_capacity=cap_name, target_capacity=tgt_capacity
238
- )
239
- migrate_spark_settings(
240
- source_capacity=cap_name, target_capacity=tgt_capacity
241
- )
251
+ migrate_settings(source_capacity=cap_name, target_capacity=tgt_capacity)
242
252
 
243
253
 
244
254
  @log
@@ -252,24 +262,21 @@ def migrate_capacity_settings(source_capacity: str, target_capacity: str):
252
262
  Name of the source capacity.
253
263
  target_capacity : str
254
264
  Name of the target capacity.
255
-
256
- Returns
257
- -------
258
265
  """
259
266
 
260
- dfC = fabric.list_capacities()
261
- dfC_filt = dfC[dfC["Display Name"] == source_capacity]
267
+ dfC = list_capacities()
268
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
262
269
  if len(dfC_filt) == 0:
263
270
  raise ValueError(
264
271
  f"{icons.red_dot} The '{source_capacity}' capacity does not exist."
265
272
  )
266
- source_capacity_id = dfC_filt["Id"].iloc[0].upper()
267
- dfC_filt = dfC[dfC["Display Name"] == target_capacity]
273
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
274
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
268
275
  if len(dfC_filt) == 0:
269
276
  raise ValueError(
270
277
  f"{icons.red_dot} The '{target_capacity}' capacity does not exist."
271
278
  )
272
- target_capacity_id = dfC_filt["Id"].iloc[0].upper()
279
+ target_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
273
280
 
274
281
  workloads_params = "capacityCustomParameters?workloadIds=ADM&workloadIds=CDSA&workloadIds=DMS&workloadIds=RsRdlEngine&workloadIds=ScreenshotEngine&workloadIds=AS&workloadIds=QES&workloadIds=DMR&workloadIds=ESGLake&workloadIds=NLS&workloadIds=lake&workloadIds=TIPS&workloadIds=Kusto&workloadIds=Lakehouse&workloadIds=SparkCore&workloadIds=DI&workloadIds=Notebook&workloadIds=ML&workloadIds=ES&workloadIds=Reflex&workloadIds=Must&workloadIds=dmh&workloadIds=PowerBI&workloadIds=HLS"
275
282
 
@@ -350,19 +357,19 @@ def migrate_disaster_recovery_settings(source_capacity: str, target_capacity: st
350
357
  Name of the target capacity.
351
358
  """
352
359
 
353
- dfC = fabric.list_capacities()
354
- dfC_filt = dfC[dfC["Display Name"] == source_capacity]
360
+ dfC = list_capacities()
361
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
355
362
  if len(dfC_filt) == 0:
356
363
  raise ValueError(
357
364
  f"{icons.red_dot} The '{source_capacity}' capacity does not exist."
358
365
  )
359
- source_capacity_id = dfC_filt["Id"].iloc[0].upper()
360
- dfC_filt = dfC[dfC["Display Name"] == target_capacity]
366
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
367
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
361
368
  if len(dfC_filt) == 0:
362
369
  raise ValueError(
363
370
  f"{icons.red_dot} The '{target_capacity}' capacity does not exist."
364
371
  )
365
- target_capacity_id = dfC_filt["Id"].iloc[0].upper()
372
+ target_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
366
373
 
367
374
  client = fabric.PowerBIRestClient()
368
375
  response_get_source = client.get(f"capacities/{source_capacity_id}/config")
@@ -395,24 +402,21 @@ def migrate_access_settings(source_capacity: str, target_capacity: str):
395
402
  Name of the source capacity.
396
403
  target_capacity : str
397
404
  Name of the target capacity.
398
-
399
- Returns
400
- -------
401
405
  """
402
406
 
403
- dfC = fabric.list_capacities()
404
- dfC_filt = dfC[dfC["Display Name"] == source_capacity]
407
+ dfC = list_capacities()
408
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
405
409
  if len(dfC_filt) == 0:
406
410
  raise ValueError(
407
411
  f"{icons.red_dot} The '{source_capacity}' capacity does not exist."
408
412
  )
409
- source_capacity_id = dfC_filt["Id"].iloc[0].upper()
410
- dfC_filt = dfC[dfC["Display Name"] == target_capacity]
413
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
414
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
411
415
  if len(dfC_filt) == 0:
412
416
  raise ValueError(
413
417
  f"{icons.red_dot} The '{target_capacity}' capacity does not exist."
414
418
  )
415
- target_capacity_id = dfC_filt["Id"].iloc[0].upper()
419
+ target_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
416
420
 
417
421
  client = fabric.PowerBIRestClient()
418
422
  response_get_source = client.get(f"capacities/{source_capacity_id}")
@@ -444,24 +448,21 @@ def migrate_notification_settings(source_capacity: str, target_capacity: str):
444
448
  Name of the source capacity.
445
449
  target_capacity : str
446
450
  Name of the target capacity.
447
-
448
- Returns
449
- -------
450
451
  """
451
452
 
452
- dfC = fabric.list_capacities()
453
- dfC_filt = dfC[dfC["Display Name"] == source_capacity]
453
+ dfC = list_capacities()
454
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
454
455
  if len(dfC_filt) == 0:
455
456
  raise ValueError(
456
457
  f"{icons.red_dot} The '{source_capacity}' capacity does not exist."
457
458
  )
458
- source_capacity_id = dfC_filt["Id"].iloc[0].upper()
459
- dfC_filt = dfC[dfC["Display Name"] == target_capacity]
459
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
460
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
460
461
  if len(dfC_filt) == 0:
461
462
  raise ValueError(
462
463
  f"{icons.red_dot} The '{target_capacity}' capacity does not exist."
463
464
  )
464
- target_capacity_id = dfC_filt["Id"].iloc[0].upper()
465
+ target_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
465
466
 
466
467
  client = fabric.PowerBIRestClient()
467
468
  response_get_source = client.get(f"capacities/{source_capacity_id}")
@@ -495,26 +496,23 @@ def migrate_delegated_tenant_settings(source_capacity: str, target_capacity: str
495
496
  Name of the source capacity.
496
497
  target_capacity : str
497
498
  Name of the target capacity.
498
-
499
- Returns
500
- -------
501
499
  """
502
500
 
503
- dfC = fabric.list_capacities()
501
+ dfC = list_capacities()
504
502
 
505
- dfC_filt = dfC[dfC["Display Name"] == source_capacity]
503
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
506
504
  if len(dfC_filt) == 0:
507
505
  raise ValueError(
508
506
  f"{icons.red_dot} The '{source_capacity}' capacity does not exist."
509
507
  )
510
- source_capacity_id = dfC_filt["Id"].iloc[0].upper()
508
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
511
509
 
512
- dfC_filt = dfC[dfC["Display Name"] == target_capacity]
510
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
513
511
  if len(dfC_filt) == 0:
514
512
  raise ValueError(
515
513
  f"{icons.red_dot} The '{target_capacity}' capacity does not exist."
516
514
  )
517
- target_capacity_id = dfC_filt["Id"].iloc[0].upper()
515
+ target_capacity_id = dfC_filt["Capacity Id"].iloc[0].upper()
518
516
 
519
517
  client = fabric.FabricRestClient()
520
518
  response_get = client.get("v1/admin/capacities/delegatedTenantSettingOverrides")
@@ -621,3 +619,106 @@ def migrate_spark_settings(source_capacity: str, target_capacity: str):
621
619
  print(
622
620
  f"{icons.green_dot} The spark settings have been migrated from the '{source_capacity}' capacity to the '{target_capacity}' capacity."
623
621
  )
622
+
623
+
624
+ @log
625
+ def migrate_fabric_trial_capacity(
626
+ azure_subscription_id: str,
627
+ key_vault_uri: str,
628
+ key_vault_tenant_id: str,
629
+ key_vault_client_id: str,
630
+ key_vault_client_secret: str,
631
+ resource_group: str,
632
+ source_capacity: str,
633
+ target_capacity: str,
634
+ target_capacity_sku: str = "F64",
635
+ target_capacity_admin_members: Optional[str | List[str]] = None,
636
+ ):
637
+ """
638
+ This function migrates a Fabric trial capacity to a Fabric capacity. If the 'target_capacity' does not exist, it is created with the relevant target capacity parameters (sku, region, admin members).
639
+
640
+ Parameters
641
+ ----------
642
+ azure_subscription_id : str
643
+ The Azure subscription ID.
644
+ key_vault_uri : str
645
+ The name of the `Azure key vault <https://azure.microsoft.com/products/key-vault>`_ URI. Example: "https://<Key Vault Name>.vault.azure.net/"
646
+ key_vault_tenant_id : str
647
+ The name of the Azure key vault secret storing the Tenant ID.
648
+ key_vault_client_id : str
649
+ The name of the Azure key vault secret storing the Client ID.
650
+ key_vault_client_secret : str
651
+ The name of the Azure key vault secret storing the Client Secret.
652
+ resource_group : str
653
+ The name of the Azure resource group.
654
+ source_capacity : str
655
+ The name of the Fabric trial capacity.
656
+ target_capacity : str
657
+ The name of the new Fabric capacity (F SKU). If this capacity does not exist, it will be created.
658
+ target_capacity_sku : str, default="F64"
659
+ If the target capacity does not exist, this property sets the SKU size for the target capacity.
660
+ target_capacity_admin_members : str, default=None
661
+ If the target capacity does not exist, this property sets the admin members for the target capacity.
662
+ Defaults to None which resolves to the admin members on the Trial SKU.
663
+ """
664
+
665
+ notebook_workspace_id = fabric.get_notebook_workspace_id()
666
+ dfW = fabric.list_workspaces(filter=f"id eq '{notebook_workspace_id}'")
667
+ notebook_capacity_id = dfW["Capacity Id"].iloc[0].lower()
668
+
669
+ dfC = list_capacities()
670
+ dfC_filt = dfC[dfC["Capacity Name"] == source_capacity]
671
+
672
+ if len(dfC_filt) == 0:
673
+ raise ValueError(
674
+ f"{icons.red_dot} The {source_capacity}' capacity does not exist."
675
+ )
676
+
677
+ source_capacity_sku = dfC_filt["Sku"].iloc[0]
678
+ if not source_capacity_sku.startswith("FT"):
679
+ raise ValueError(
680
+ f"{icons.red_dot} This function is for migrating Fabric trial capacites to Fabric capacities."
681
+ )
682
+
683
+ source_capacity_id = dfC_filt["Capacity Id"].iloc[0].lower()
684
+ if source_capacity_id == notebook_capacity_id:
685
+ print(
686
+ f"{icons.warning} The '{source_capacity}' capacity cannot be both the source capacity as well as the capacity in which the notebook is running."
687
+ )
688
+ return
689
+
690
+ target_capacity_region = dfC_filt["Region"].iloc[0]
691
+
692
+ # Use same admins as source capacity
693
+ if isinstance(target_capacity_admin_members, str):
694
+ target_capacity_admin_members = [target_capacity_admin_members]
695
+
696
+ if target_capacity_admin_members is None:
697
+ target_capacity_admin_members = dfC_filt["Admins"].iloc[0]
698
+
699
+ dfC_filt = dfC[dfC["Capacity Name"] == target_capacity]
700
+ if len(dfC_filt) == 0:
701
+ create_fabric_capacity(
702
+ capacity_name=target_capacity,
703
+ azure_subscription_id=azure_subscription_id,
704
+ key_vault_uri=key_vault_uri,
705
+ key_vault_tenant_id=key_vault_tenant_id,
706
+ key_vault_client_id=key_vault_client_id,
707
+ key_vault_client_secret=key_vault_client_secret,
708
+ resource_group=resource_group,
709
+ region=target_capacity_region,
710
+ admin_members=target_capacity_admin_members,
711
+ sku=target_capacity_sku,
712
+ )
713
+
714
+ assign_workspaces_to_capacity(
715
+ source_capacity=source_capacity,
716
+ target_capacity=target_capacity,
717
+ workspace=None,
718
+ )
719
+
720
+ # This migrates all the capacity settings
721
+ migrate_settings(
722
+ source_capacity=source_capacity,
723
+ target_capacity=target_capacity,
724
+ )