Skip to content
3 changes: 2 additions & 1 deletion src/fabric_cli/core/fab_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
)

API_ENDPOINT_POWER_BI = (
validate_and_get_env_variable("FAB_API_ENDPOINT_POWER_BI", "api.powerbi.com")
validate_and_get_env_variable(
"FAB_API_ENDPOINT_POWER_BI", "api.powerbi.com")
+ "/v1.0/myorg"
)

Expand Down
100 changes: 59 additions & 41 deletions src/fabric_cli/core/fab_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import json
import re

# Default error constants - avoids circular imports
DEFAULT_ERROR_MESSAGE = "An error occurred while processing the operation"
DEFAULT_ERROR_CODE = "UnknownError"


class FabricCLIError(Exception):
def __init__(self, message, status_code=None):
super().__init__(message)
self.message = message.rstrip(".")
self.message = message.rstrip(".") if message else None
Comment thread
v-alexmoraru marked this conversation as resolved.
Outdated
self.status_code = status_code
Comment thread
v-alexmoraru marked this conversation as resolved.
Outdated

def __str__(self):
Expand All @@ -20,7 +24,7 @@ def __str__(self):
)

def formatted_message(self, verbose=False):
escaped_text = html.escape(self.message)
escaped_text = html.escape(self.message) if self.message else ""

return (
f"[{self.status_code}] {escaped_text}"
Expand Down Expand Up @@ -63,12 +67,17 @@ def __init__(self, response_text):
related_resource (dict): Details about the main related resource, if available.
request_id (str): The ID of the request associated with the error.
"""
response = json.loads(response_text)
message = response.get("message")
error_code = response.get("errorCode")

self.more_details: list[dict] = response.get("moreDetails", [])
self.request_id = response.get("requestId")
try:
response = json.loads(response_text) if response_text else {}
message = response.get("message")
error_code = response.get("errorCode")
self.more_details: list[dict] = response.get("moreDetails", [])
self.request_id = response.get("requestId")
except (json.JSONDecodeError, TypeError):
message = DEFAULT_ERROR_MESSAGE
error_code = DEFAULT_ERROR_CODE
self.more_details = []
self.request_id = None

super().__init__(message, error_code)

Expand Down Expand Up @@ -111,27 +120,31 @@ def __init__(self, response_text):
code (str): The error code returned by the API.
message (str): A descriptive message about the error.
"""
response_data = json.loads(response_text)
error_data = response_data.get("error", {})
code = error_data.get("code")
message = error_data.get("message")

if message:
message = re.sub(r"\n(?=RequestId:)", "", message)
match = re.search(r"RequestId:(\S+)", message)
if match:
self.request_id = match.group(1)
message = message.replace(match.group(0), "")
else:
self.request_id = None

message = re.sub(r"\n(?=Time:)", "", message)
match = re.search(r"Time:(\S+)", message)
if match:
self.timestamp = match.group(1)
message = message.replace(match.group(0), "")
else:
self.timestamp = None
# Initialize properties before parsing
self.request_id = None
self.timestamp = None

try:
response_data = json.loads(response_text) if response_text else {}
error_data = response_data.get("error", {})
code = error_data.get("code")
message = error_data.get("message")

if message:
message = re.sub(r"\n(?=RequestId:)", "", message)
match = re.search(r"RequestId:(\S+)", message)
if match:
self.request_id = match.group(1)
message = message.replace(match.group(0), "")

message = re.sub(r"\n(?=Time:)", "", message)
match = re.search(r"Time:(\S+)", message)
if match:
self.timestamp = match.group(1)
message = message.replace(match.group(0), "")
except (json.JSONDecodeError, TypeError):
message = DEFAULT_ERROR_MESSAGE
code = DEFAULT_ERROR_CODE

super().__init__(message, code)

Expand Down Expand Up @@ -188,19 +201,24 @@ def __init__(self, response_text):
details (list): A list of additional error details, if available.
additional_info (list): Additional info at the main error level, if available.
"""
response_data = json.loads(response_text)
error_data = response_data.get("error", {})
code = error_data.get("code")
message = error_data.get("message")

details: list[dict] = error_data.get("details", [])

# Extract RootActivityId from the details
# Initialize properties before parsing
self.request_id = None
for detail in details:
if detail.get("code") == "RootActivityId":
self.request_id = detail.get("message")
break

try:
response_data = json.loads(response_text) if response_text else {}
error_data = response_data.get("error", {})
code = error_data.get("code")
message = error_data.get("message")

details: list[dict] = error_data.get("details", [])

for detail in details:
if detail.get("code") == "RootActivityId":
self.request_id = detail.get("message")
break
except (json.JSONDecodeError, TypeError):
message = DEFAULT_ERROR_MESSAGE
code = DEFAULT_ERROR_CODE

super().__init__(message, code)

Expand Down
11 changes: 11 additions & 0 deletions tests/test_commands/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import argparse
import os
import platform
import time
from unittest.mock import ANY, patch

import pytest
Expand Down Expand Up @@ -847,6 +848,11 @@ def _import_create_new_item_success(
):
# Setup
item = item_factory(item_type)

# TODO: delete this line after mirrored db fix the API GAP for Create
if item_type == ItemType.MIRRORED_DATABASE:
time.sleep(60)
Comment thread
v-alexmoraru marked this conversation as resolved.

export(item.full_path, output=os.path.expanduser(str(tmp_path)))

# Reset mock
Expand Down Expand Up @@ -891,6 +897,11 @@ def _import_update_existing_item_success(
):
# Setup
item = item_factory(item_type)

# TODO: delete this line after mirrored db fix the API GAP for Create
if item_type == ItemType.MIRRORED_DATABASE:
time.sleep(60)

export(item.full_path, output=str(tmp_path))

# Reset mock
Expand Down