Skip to content

Commit

Permalink
Merge branch 'main' into FT-790
Browse files Browse the repository at this point in the history
  • Loading branch information
Aryamanz29 authored Dec 12, 2024
2 parents 46b3522 + 14a7457 commit 7d68d77
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 29 deletions.
23 changes: 22 additions & 1 deletion pyatlan/client/atlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,11 +421,32 @@ def _call_api_internal(
error_message = error_info.get(
"errorMessage", ""
) or error_info.get("message", "")
causes = error_info.get("causes", [])
backend_error_id = error_info.get("errorId")

# Handle the causes and format them for exception
error_cause_details = [
f"ErrorType: {cause.get('errorType', 'Unknown')}, "
f"Message: {cause.get('errorMessage', 'No additional information provided')}, "
f"Location: {cause.get('location', 'Unknown location')}"
for cause in causes
]
# Join the error cause details into a single string, separated by newlines
error_cause_details_str = (
"\n".join(error_cause_details) if error_cause_details else ""
)

if error_code and error_message:
error = ERROR_CODE_FOR_HTTP_STATUS.get(
response.status_code, ErrorCode.ERROR_PASSTHROUGH
)
raise error.exception_with_parameters(error_code, error_message)
# Raise exception with error details and causes
raise error.exception_with_parameters(
error_code,
error_message,
error_cause_details_str,
backend_error_id=backend_error_id,
)
raise AtlanError(
SimpleNamespace(
http_error_code=response.status_code,
Expand Down
35 changes: 22 additions & 13 deletions pyatlan/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from enum import Enum
from typing import Dict, Protocol, Type, TypeVar
from typing import Dict, List, Protocol, Type, TypeVar

E = TypeVar("E", bound="AtlanError")
RAISE_GITHUB_ISSUE = (
Expand All @@ -17,21 +17,30 @@ class ErrorInfo(Protocol):
error_id: str
error_message: str
user_action: str
# Causes underlying the error
# if any (provided by the back-end)
error_causes: List[str]
# Unique identifier for the error
# (provided by the back-end)
backend_error_id: str


class AtlanError(Exception):
def __init__(self, error_code: ErrorInfo, *args):
def __init__(self, error_code: ErrorInfo, *args, **kwargs):
try:
message = error_code.error_message.format(*args)
except (KeyError, ValueError):
message = error_code.error_message
super().__init__(message)
self.error_code = error_code
self.error_code.backend_error_id = kwargs.get("backend_error_id", "")

def __str__(self):
return (
f"{self.error_code.error_id or ''} "
f"{super().__str__()} Suggestion: {self.error_code.user_action}"
f"{self.error_code.error_id or ''}"
f"{' ' if self.error_code.error_id else ''}{super().__str__()}"
f"{' (errorId: ' + self.error_code.backend_error_id + ')' if self.error_code.backend_error_id else ''}"
f" Suggestion: {self.error_code.user_action}"
)


Expand Down Expand Up @@ -95,7 +104,7 @@ class ErrorCode(Enum):
INVALID_REQUEST_PASSTHROUGH = (
400,
"ATLAN-PYTHON-400-000",
"Server responded with {0}: {1}.",
"Server responded with an invalid request {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
InvalidRequestError,
)
Expand Down Expand Up @@ -572,7 +581,7 @@ class ErrorCode(Enum):
AUTHENTICATION_PASSTHROUGH = (
401,
"ATLAN-PYTHON-401-000",
"Server responded with {0}: {1}.",
"Server responded with an authentication error {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
AuthenticationError,
)
Expand Down Expand Up @@ -616,7 +625,7 @@ class ErrorCode(Enum):
PERMISSION_PASSTHROUGH = (
403,
"ATLAN-PYTHON-403-000",
"Server responded with {0}: {1}.",
"Server responded with a permission error {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
PermissionError,
)
Expand All @@ -637,7 +646,7 @@ class ErrorCode(Enum):
NOT_FOUND_PASSTHROUGH = (
404,
"ATLAN-PYTHON-404-000",
"Server responded with {0}: {1}.",
"Server responded with a not found error {0}: {1}.",
"Check the details of the server's message to correct your request.",
NotFoundError,
)
Expand Down Expand Up @@ -848,7 +857,7 @@ class ErrorCode(Enum):
CONFLICT_PASSTHROUGH = (
409,
"ATLAN-PYTHON-409-000",
"Server responded with {0}: {1}.",
"Server responded with a conflict {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
ConflictError,
)
Expand All @@ -864,14 +873,14 @@ class ErrorCode(Enum):
RATE_LIMIT_PASSTHROUGH = (
429,
"ATLAN-PYTHON-429-000",
"Server responded with {0}: {1}.",
"Server responded with a rate limit violation {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
RateLimitError,
)
ERROR_PASSTHROUGH = (
500,
"ATLAN-PYTHON-500-000",
"Server responded with {0}: {1}.",
"Server responded with an error {0}: {1} -- caused by: {2}",
"Check the details of the server's message to correct your request.",
ApiError,
)
Expand Down Expand Up @@ -926,8 +935,8 @@ def __init__(
self.user_action = user_action
self.exception_type = exception_type

def exception_with_parameters(self, *args):
return self.exception_type(self, *args)
def exception_with_parameters(self, *args, **kwargs):
return self.exception_type(self, *args, **kwargs)


ERROR_CODE_FOR_HTTP_STATUS: Dict[int, ErrorCode] = {
Expand Down
8 changes: 7 additions & 1 deletion pyatlan/generator/templates/methods/attribute/column.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@
parent_qualified_name
)
column.table_name = table_name
elif parent_type == SnowflakeDynamicTable:
column.table_qualified_name = parent_qualified_name
column.snowflake_dynamic_table = (
SnowflakeDynamicTable.ref_by_qualified_name(parent_qualified_name)
)
column.table_name = parent_name
else:
raise ValueError(
"parent_type must be either Table, View, MaterializeView or TablePartition"
"parent_type must be either Table, SnowflakeDynamicTable, View, MaterializeView or TablePartition"
)
return column
8 changes: 7 additions & 1 deletion pyatlan/model/assets/core/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -1594,9 +1594,15 @@ def create(
parent_qualified_name
)
column.table_name = table_name
elif parent_type == SnowflakeDynamicTable:
column.table_qualified_name = parent_qualified_name
column.snowflake_dynamic_table = (
SnowflakeDynamicTable.ref_by_qualified_name(parent_qualified_name)
)
column.table_name = parent_name
else:
raise ValueError(
"parent_type must be either Table, View, MaterializeView or TablePartition"
"parent_type must be either Table, SnowflakeDynamicTable, View, MaterializeView or TablePartition"
)
return column

Expand Down
6 changes: 3 additions & 3 deletions tests/integration/glossary_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ def test_term_failure(
):
with pytest.raises(
NotFoundError,
match="ATLAN-PYTHON-404-000 Server responded with ATLAS-404-00-009: Instance AtlasGlossaryTerm with "
"unique attribute *",
match="ATLAN-PYTHON-404-000 Server responded with a not found "
"error ATLAS-404-00-009: Instance AtlasGlossaryTerm with unique attribute *",
):
client.asset.update_merging_cm(
AtlasGlossaryTerm.create(
Expand Down Expand Up @@ -943,7 +943,7 @@ def test_remove_unrelated_relationship(
client.asset.save(term)

EXPECTED_ERR = (
"ATLAN-PYTHON-404-000 Server responded with ATLAS-409-00-0021: "
"ATLAN-PYTHON-404-000 Server responded with a not found error ATLAS-409-00-0021: "
"relationship AtlasGlossaryRelatedTerm does "
f"not exist between entities {term2.guid} and {term1.guid}. "
"Suggestion: Check the details of the server's message to correct your request."
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@ def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error(
):
with pytest.raises(
NotFoundError,
match="ATLAN-PYTHON-404-000 Server responded with ATLAS-404-00-005: Given instance guid 76d54dd6 "
"is invalid/not found",
match="ATLAN-PYTHON-404-000 Server responded with a not found "
"error ATLAS-404-00-005: Given instance guid 76d54dd6 is invalid/not found",
):
client.asset.get_by_guid("76d54dd6", AtlasGlossary)

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/model/a_p_i_object_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from tests.unit.model.constants import (
API_CONNECTION_QUALIFIED_NAME,
API_CONNECTOR_TYPE,
API_OBJECT_QUALIFIED_NAME,
API_OBJECT_NAME,
API_OBJECT_QUALIFIED_NAME,
)


Expand Down
2 changes: 1 addition & 1 deletion tests/unit/model/a_p_i_query_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from tests.unit.model.constants import (
API_CONNECTION_QUALIFIED_NAME,
API_CONNECTOR_TYPE,
API_QUERY_QUALIFIED_NAME,
API_QUERY_NAME,
API_QUERY_QUALIFIED_NAME,
API_QUERY_REFERENCE_OBJECT_QN,
)

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/model/application_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from pyatlan.model.assets import Application
from tests.unit.model.constants import (
APPLICATION_NAME,
APPLICATION_QUALIFIED_NAME,
APP_CONNECTION_QUALIFIED_NAME,
APP_CONNECTOR_TYPE,
APPLICATION_NAME,
APPLICATION_QUALIFIED_NAME,
)


Expand Down
32 changes: 30 additions & 2 deletions tests/unit/model/column_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import pytest

from pyatlan.model.assets import Column, MaterialisedView, Table, View
from pyatlan.model.assets import (
Column,
MaterialisedView,
SnowflakeDynamicTable,
Table,
View,
)
from tests.unit.model.constants import (
COLUMN_NAME,
CONNECTION_QUALIFIED_NAME,
Expand Down Expand Up @@ -59,7 +65,7 @@
TABLE_QUALIFIED_NAME,
Column,
1,
"parent_type must be either Table, View, MaterializeView or TablePartition",
"parent_type must be either Table, SnowflakeDynamicTable, View, MaterializeView or TablePartition",
),
],
)
Expand Down Expand Up @@ -97,6 +103,28 @@ def test_create_when_parent_is_table():
assert sut.table_name == TABLE_NAME


def test_create_when_parent_is_snowflake_dynamic_table():
sut = Column.create(
name=COLUMN_NAME,
parent_qualified_name=TABLE_QUALIFIED_NAME,
parent_type=SnowflakeDynamicTable,
order=1,
)

assert sut.name == COLUMN_NAME
assert sut.qualified_name == TABLE_COLUMN_QUALIFIED_NAME
assert sut.connector_name == CONNECTOR_TYPE
assert sut.schema_name == SCHEMA_NAME
assert sut.schema_qualified_name == SCHEMA_QUALIFIED_NAME
assert sut.database_name == DATABASE_NAME
assert sut.database_qualified_name == DATABASE_QUALIFIED_NAME
assert sut.connection_qualified_name == CONNECTION_QUALIFIED_NAME
assert sut.order == 1
assert sut.table_qualified_name == TABLE_QUALIFIED_NAME
assert sut.snowflake_dynamic_table.qualified_name == TABLE_QUALIFIED_NAME
assert sut.table_name == TABLE_NAME


def test_create_when_parent_is_view():
sut = Column.create(
name=COLUMN_NAME,
Expand Down
Loading

0 comments on commit 7d68d77

Please sign in to comment.