From 58e7fd6a4168432337b206baef4460929afb31c3 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 12:54:24 +0530 Subject: [PATCH 01/66] Changed ignore_relationships = True by default and added fluent search support for when attributes or relationships_attributes are present --- pyatlan/client/asset.py | 157 ++++++++++++++++++++++++++++++++++------ testing.py | 26 +++++++ 2 files changed, 160 insertions(+), 23 deletions(-) create mode 100644 testing.py diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index df6ce9cb..874cbe0d 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -357,7 +357,9 @@ def get_by_qualified_name( qualified_name: str, asset_type: Type[A], min_ext_info: bool = False, - ignore_relationships: bool = False, + ignore_relationships: bool = True, + attributes: Optional[List[str]] = None, + relationships_attributes: Optional[List[str]] = None, ) -> A: """ Retrieves an asset by its qualified_name. @@ -366,29 +368,88 @@ def get_by_qualified_name( :param asset_type: type of asset to be retrieved ( must be the actual asset type not a super type) :param min_ext_info: whether to minimize extra info (True) or not (False) :param ignore_relationships: whether to include relationships (False) or exclude them (True) + :param attributes: a specific list of attributes to retrieve for the asset + :param relationships_attributes: a specific list of relationships attributes to retrieve for the asset :returns: the requested asset :raises NotFoundError: if the asset does not exist :raises AtlanError: on any API communication issue """ + from pyatlan.client.atlan import AtlanClient + from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + query_params = { "attr:qualifiedName": qualified_name, "minExtInfo": min_ext_info, "ignoreRelationships": ignore_relationships, } - raw_json = self._client._call_api( - GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params(asset_type.__name__), - query_params, - ) - if raw_json["entity"]["typeName"] != asset_type.__name__: - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name + if ( + (not attributes or not len(attributes)) + and (not relationships_attributes or not len(relationships_attributes)) + and (min_ext_info or not ignore_relationships) + ): + raw_json = self._client._call_api( + GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( + asset_type.__name__ + ), + query_params, ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name + if raw_json["entity"]["typeName"] != asset_type.__name__: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + return asset + + elif (attributes and len(attributes)) or ( + relationships_attributes and len(relationships_attributes) + ): + client = AtlanClient.get_default_client() + search = ( + FluentSearch() + .select() + .where(CompoundQuery.active_assets()) + .where(Asset.QUALIFIED_NAME.eq(qualified_name)) ) - return asset + if attributes: + for attribute in attributes: + search = search.include_on_results(attribute) + if relationships_attributes: + for relation_attribute in relationships_attributes: + search = search.include_on_relations(relation_attribute) + results = search.execute(client=client) + if results and results.current_page(): + first_result = results.current_page()[0] + if isinstance(first_result, asset_type): + return first_result + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( + qualified_name, asset_type.__name__ + ) + else: + raw_json = self._client._call_api( + GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( + asset_type.__name__ + ), + query_params, + ) + if raw_json["entity"]["typeName"] != asset_type.__name__: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + return asset @validate_arguments def get_by_guid( @@ -396,7 +457,9 @@ def get_by_guid( guid: str, asset_type: Type[A] = Asset, # type: ignore[assignment] min_ext_info: bool = False, - ignore_relationships: bool = False, + ignore_relationships: bool = True, + attributes: Optional[List[str]] = None, + relationships_attributes: Optional[List[str]] = None, ) -> A: """ Retrieves an asset by its GUID. @@ -406,24 +469,72 @@ def get_by_guid( :param min_ext_info: whether to minimize extra info (True) or not (False) :param ignore_relationships: whether to include relationships (False) or exclude them (True) :returns: the requested asset + :param attributes: a specific list of attributes to retrieve for the asset + :param relationships_attributes: a specific list of relationships attributes to retrieve for the asset :raises NotFoundError: if the asset does not exist, or is not of the type requested :raises AtlanError: on any API communication issue """ + from pyatlan.client.atlan import AtlanClient + from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + query_params = { "minExtInfo": min_ext_info, "ignoreRelationships": ignore_relationships, } + if ( + (not attributes or not len(attributes)) + and (not relationships_attributes or not len(relationships_attributes)) + and (min_ext_info or not ignore_relationships) + ): + raw_json = self._client._call_api( + GET_ENTITY_BY_GUID.format_path_with_params(guid), + query_params, + ) + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + return asset - raw_json = self._client._call_api( - GET_ENTITY_BY_GUID.format_path_with_params(guid), - query_params, - ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( - guid, asset_type.__name__ + elif (attributes and len(attributes)) or ( + relationships_attributes and len(relationships_attributes) + ): + client = AtlanClient.get_default_client() + search = ( + FluentSearch() + .select() + .where(CompoundQuery.active_assets()) + .where(Asset.GUID.eq(guid)) ) - return asset + if attributes: + for attribute in attributes: + search = search.include_on_results(attribute) + if relationships_attributes: + for relation_attribute in relationships_attributes: + search = search.include_on_relations(relation_attribute) + results = search.execute(client=client) + if results and results.current_page(): + first_result = results.current_page()[0] + if isinstance(first_result, asset_type): + return first_result + else: + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) + else: + raw_json = self._client._call_api( + GET_ENTITY_BY_GUID.format_path_with_params(guid), + query_params, + ) + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + return asset def _handle_relationships(self, raw_json): if ( diff --git a/testing.py b/testing.py new file mode 100644 index 00000000..db354b3a --- /dev/null +++ b/testing.py @@ -0,0 +1,26 @@ +from pyatlan.client.atlan import AtlanClient + +# GUID="3e939271-abbd-42bf-9188-9cff9ee36387" +# request = FluentSearch().select().where(Asset.GUID.eq(GUID)) +# .include_on_results(["qualified_name","name"]).execute(client) + +# candidate = (response.current_page() and response.current_page()[0]) or None +# print(candidate) + +client = AtlanClient() + +response = client.asset.get_by_guid(guid="3e939271-abbd-42bf-9188-9cff9ee36387") +print(response) +print("next") +# client = AtlanClient() + +# GUID = "3e939271-abbd-42bf-9188-9cff9ee36387" +# request = ( +# FluentSearch() +# .select() +# .where(Asset.GUID.eq(GUID)) +# .include_on_results(["qualified_name", "name"]) # Ensure all elements are strings +# .execute(client) +# ) + +# print(request) From 5e61d92020b2ab938f19b28af32ff6bf955f3274 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 13:04:05 +0530 Subject: [PATCH 02/66] approach changed --- pyatlan/client/asset.py | 94 ++++++++++++----------------------------- 1 file changed, 28 insertions(+), 66 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 874cbe0d..20eba8d4 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -382,29 +382,7 @@ def get_by_qualified_name( "minExtInfo": min_ext_info, "ignoreRelationships": ignore_relationships, } - if ( - (not attributes or not len(attributes)) - and (not relationships_attributes or not len(relationships_attributes)) - and (min_ext_info or not ignore_relationships) - ): - raw_json = self._client._call_api( - GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( - asset_type.__name__ - ), - query_params, - ) - if raw_json["entity"]["typeName"] != asset_type.__name__: - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name - ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name - ) - return asset - - elif (attributes and len(attributes)) or ( + if (attributes and len(attributes)) or ( relationships_attributes and len(relationships_attributes) ): client = AtlanClient.get_default_client() @@ -433,23 +411,23 @@ def get_by_qualified_name( raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( qualified_name, asset_type.__name__ ) - else: - raw_json = self._client._call_api( - GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( - asset_type.__name__ - ), - query_params, + + raw_json = self._client._call_api( + GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( + asset_type.__name__ + ), + query_params, + ) + if raw_json["entity"]["typeName"] != asset_type.__name__: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name ) - if raw_json["entity"]["typeName"] != asset_type.__name__: - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name - ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( - asset_type.__name__, qualified_name - ) - return asset + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + return asset @validate_arguments def get_by_guid( @@ -481,23 +459,7 @@ def get_by_guid( "minExtInfo": min_ext_info, "ignoreRelationships": ignore_relationships, } - if ( - (not attributes or not len(attributes)) - and (not relationships_attributes or not len(relationships_attributes)) - and (min_ext_info or not ignore_relationships) - ): - raw_json = self._client._call_api( - GET_ENTITY_BY_GUID.format_path_with_params(guid), - query_params, - ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( - guid, asset_type.__name__ - ) - return asset - - elif (attributes and len(attributes)) or ( + if (attributes and len(attributes)) or ( relationships_attributes and len(relationships_attributes) ): client = AtlanClient.get_default_client() @@ -524,17 +486,17 @@ def get_by_guid( ) else: raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) - else: - raw_json = self._client._call_api( - GET_ENTITY_BY_GUID.format_path_with_params(guid), - query_params, + + raw_json = self._client._call_api( + GET_ENTITY_BY_GUID.format_path_with_params(guid), + query_params, + ) + asset = self._handle_relationships(raw_json) + if not isinstance(asset, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ ) - asset = self._handle_relationships(raw_json) - if not isinstance(asset, asset_type): - raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( - guid, asset_type.__name__ - ) - return asset + return asset def _handle_relationships(self, raw_json): if ( From 05c3ece979a4bfac30acc00990433285702793e9 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 13:22:11 +0530 Subject: [PATCH 03/66] Fixed QA checks --- pyatlan/client/asset.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 20eba8d4..534c9314 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -411,11 +411,9 @@ def get_by_qualified_name( raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( qualified_name, asset_type.__name__ ) - + raw_json = self._client._call_api( - GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params( - asset_type.__name__ - ), + GET_ENTITY_BY_UNIQUE_ATTRIBUTE.format_path_with_params(asset_type.__name__), query_params, ) if raw_json["entity"]["typeName"] != asset_type.__name__: From 9b5ca3e69fa4d2fe8103cfad273d2ef5ce53386b Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 14:37:26 +0530 Subject: [PATCH 04/66] Fixed failing integration tests due to the breaking change --- pyatlan/client/asset.py | 10 +++--- pyatlan/samples/events/lambda_scorer.py | 2 +- pyatlan/test_utils/__init__.py | 2 +- tests/integration/adls_asset_test.py | 6 ++-- tests/integration/airflow_asset_test.py | 6 ++-- tests/integration/api_asset_test.py | 24 ++++++------- tests/integration/app_asset_test.py | 5 +-- .../integration/azure_event_hub_asset_test.py | 5 +-- tests/integration/connection_test.py | 2 +- tests/integration/custom_metadata_test.py | 2 +- tests/integration/data_mesh_test.py | 14 ++++---- tests/integration/data_studio_asset_test.py | 6 ++-- tests/integration/file_test.py | 2 +- tests/integration/gcs_asset_test.py | 6 ++-- tests/integration/glossary_test.py | 22 ++++++------ tests/integration/kafka_asset_test.py | 6 ++-- tests/integration/lineage_test.py | 4 +-- tests/integration/persona_test.py | 4 +-- tests/integration/preset_asset_test.py | 4 +-- tests/integration/purpose_test.py | 6 ++-- tests/integration/s3_asset_test.py | 6 ++-- tests/integration/superset_asset_test.py | 4 +-- tests/integration/test_client.py | 34 +++++++++---------- tests/integration/test_index_search.py | 2 +- tests/integration/test_sql_assets.py | 32 ++++++++--------- tests/integration/test_task_client.py | 2 +- tests/integration/utils.py | 2 +- tests/unit/test_client.py | 2 +- 28 files changed, 112 insertions(+), 110 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 534c9314..b1980ef5 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -814,7 +814,7 @@ def _restore(self, asset_type: Type[A], qualified_name: str, retries: int) -> bo if not asset_type.can_be_archived(): return False existing = self.get_by_qualified_name( - asset_type=asset_type, qualified_name=qualified_name + asset_type=asset_type, qualified_name=qualified_name, ignore_relationships=False ) if not existing: # Nothing to restore, so cannot be restored @@ -1379,10 +1379,10 @@ def replace_terms( if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid(guid=guid, asset_type=asset_type) + asset = self.get_by_guid(guid=guid, asset_type=asset_type, ignore_relationships=False) elif qualified_name: asset = self.get_by_qualified_name( - qualified_name=qualified_name, asset_type=asset_type + qualified_name=qualified_name, asset_type=asset_type, ignore_relationships=False ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() @@ -1417,10 +1417,10 @@ def remove_terms( if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid(guid=guid, asset_type=asset_type) + asset = self.get_by_guid(guid=guid, asset_type=asset_type, ignore_relationships=False) elif qualified_name: asset = self.get_by_qualified_name( - qualified_name=qualified_name, asset_type=asset_type + qualified_name=qualified_name, asset_type=asset_type, ignore_relationships=False ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() diff --git a/pyatlan/samples/events/lambda_scorer.py b/pyatlan/samples/events/lambda_scorer.py index 35106edc..b2f05c04 100644 --- a/pyatlan/samples/events/lambda_scorer.py +++ b/pyatlan/samples/events/lambda_scorer.py @@ -209,7 +209,7 @@ def calculate_changes(self, asset: Asset) -> List[Asset]: s_readme = 0 readme = asset.readme if readme and readme.guid: - readme = client.asset.get_by_guid(readme.guid, asset_type=Readme) + readme = client.asset.get_by_guid(readme.guid, asset_type=Readme, ignore_relationships=False) if description := readme.description: if len(description) > 1000: s_readme = 20 diff --git a/pyatlan/test_utils/__init__.py b/pyatlan/test_utils/__init__.py index e0855510..38f840af 100644 --- a/pyatlan/test_utils/__init__.py +++ b/pyatlan/test_utils/__init__.py @@ -112,7 +112,7 @@ def create_connection( ) response = client.asset.save(to_create) result = response.assets_created(asset_type=Connection)[0] - return client.asset.get_by_guid(result.guid, asset_type=Connection) + return client.asset.get_by_guid(result.guid, asset_type=Connection, ignore_relationships=False) def create_group(client: AtlanClient, name: str) -> CreateGroupResponse: diff --git a/tests/integration/adls_asset_test.py b/tests/integration/adls_asset_test.py index 4bf39f61..0859fe8a 100644 --- a/tests/integration/adls_asset_test.py +++ b/tests/integration/adls_asset_test.py @@ -249,7 +249,7 @@ def test_retrieve_adls_object( adls_container: ADLSContainer, adls_object: ADLSObject, ): - b = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject) + b = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == adls_object.guid @@ -319,7 +319,7 @@ def test_read_deleted_adls_object( adls_container: ADLSContainer, adls_object: ADLSObject, ): - deleted = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject) + deleted = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject, ignore_relationships=False) assert deleted assert deleted.guid == adls_object.guid assert deleted.qualified_name == adls_object.qualified_name @@ -339,7 +339,7 @@ def test_restore_object( ) assert adls_object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=ADLSObject, qualified_name=adls_object.qualified_name + asset_type=ADLSObject, qualified_name=adls_object.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == adls_object.guid diff --git a/tests/integration/airflow_asset_test.py b/tests/integration/airflow_asset_test.py index 274b5129..7e1d1df0 100644 --- a/tests/integration/airflow_asset_test.py +++ b/tests/integration/airflow_asset_test.py @@ -170,7 +170,7 @@ def test_update_airflow_assets( def _retrieve_airflow_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type) + retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -215,7 +215,7 @@ def test_read_deleted_airflow_task( client: AtlanClient, airflow_task: AirflowTask, ): - deleted = client.asset.get_by_guid(airflow_task.guid, asset_type=AirflowTask) + deleted = client.asset.get_by_guid(airflow_task.guid, asset_type=AirflowTask, ignore_relationships=False) assert deleted assert deleted.status == EntityStatus.DELETED assert deleted.guid == airflow_task.guid @@ -233,7 +233,7 @@ def test_restore_airflow_task( ) assert airflow_task.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=AirflowTask, qualified_name=airflow_task.qualified_name + asset_type=AirflowTask, qualified_name=airflow_task.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == airflow_task.guid diff --git a/tests/integration/api_asset_test.py b/tests/integration/api_asset_test.py index b0eea1ee..7a586358 100644 --- a/tests/integration/api_asset_test.py +++ b/tests/integration/api_asset_test.py @@ -187,7 +187,7 @@ def test_update_api_path( def test_retrieve_api_path( client: AtlanClient, connection: Connection, api_spec: APISpec, api_path: APIPath ): - b = client.asset.get_by_guid(api_path.guid, asset_type=APIPath) + b = client.asset.get_by_guid(api_path.guid, asset_type=APIPath, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == api_path.guid @@ -250,7 +250,7 @@ def test_delete_api_path( def test_read_deleted_api_path( client: AtlanClient, connection: Connection, api_spec: APISpec, api_path: APIPath ): - deleted = client.asset.get_by_guid(api_path.guid, asset_type=APIPath) + deleted = client.asset.get_by_guid(api_path.guid, asset_type=APIPath, ignore_relationships=False) assert deleted assert deleted.guid == api_path.guid assert deleted.qualified_name == api_path.qualified_name @@ -267,7 +267,7 @@ def test_restore_path( ) assert api_path.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIPath, qualified_name=api_path.qualified_name + asset_type=APIPath, qualified_name=api_path.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == api_path.guid @@ -365,7 +365,7 @@ def test_update_api_object( def test_retrieve_api_object( client: AtlanClient, connection: Connection, api_object_overload: APIObject ): - b = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject) + b = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == api_object_overload.guid @@ -398,7 +398,7 @@ def test_delete_api_object( def test_read_deleted_api_object( client: AtlanClient, connection: Connection, api_object_overload: APIObject ): - deleted = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject) + deleted = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject, ignore_relationships=False) assert deleted assert deleted.guid == api_object_overload.guid assert deleted.qualified_name == api_object_overload.qualified_name @@ -415,7 +415,7 @@ def test_restore_object( ) assert api_object_overload.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIObject, qualified_name=api_object_overload.qualified_name + asset_type=APIObject, qualified_name=api_object_overload.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == api_object_overload.guid @@ -597,7 +597,7 @@ def test_update_api_query( def test_retrieve_api_query( client: AtlanClient, connection: Connection, api_query_overload_3: APIQuery ): - b = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery) + b = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == api_query_overload_3.guid @@ -630,7 +630,7 @@ def test_delete_api_query( def test_read_deleted_api_query( client: AtlanClient, connection: Connection, api_query_overload_3: APIQuery ): - deleted = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery) + deleted = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False) assert deleted assert deleted.guid == api_query_overload_3.guid assert deleted.qualified_name == api_query_overload_3.qualified_name @@ -647,7 +647,7 @@ def test_restore_query( ) assert api_query_overload_3.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIQuery, qualified_name=api_query_overload_3.qualified_name + asset_type=APIQuery, qualified_name=api_query_overload_3.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == api_query_overload_3.guid @@ -989,7 +989,7 @@ def test_retrieve_api_field( api_field_parent_query_overload: APIField, ): b = client.asset.get_by_guid( - api_field_parent_query_overload.guid, asset_type=APIField + api_field_parent_query_overload.guid, asset_type=APIField, ignore_relationships=False ) assert b assert not b.is_incomplete @@ -1031,7 +1031,7 @@ def test_read_deleted_api_field( api_field_parent_query_overload: APIField, ): deleted = client.asset.get_by_guid( - api_field_parent_query_overload.guid, asset_type=APIField + api_field_parent_query_overload.guid, asset_type=APIField, ignore_relationships=False ) assert deleted assert deleted.guid == api_field_parent_query_overload.guid @@ -1053,7 +1053,7 @@ def test_restore_field( assert api_field_parent_query_overload.qualified_name restored = client.asset.get_by_qualified_name( asset_type=APIField, - qualified_name=api_field_parent_query_overload.qualified_name, + qualified_name=api_field_parent_query_overload.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == api_field_parent_query_overload.guid diff --git a/tests/integration/app_asset_test.py b/tests/integration/app_asset_test.py index 4031ca45..b7ca00a8 100644 --- a/tests/integration/app_asset_test.py +++ b/tests/integration/app_asset_test.py @@ -108,7 +108,7 @@ def test_retrieve_application( connection: Connection, application: Application, ): - b = client.asset.get_by_guid(application.guid, asset_type=Application) + b = client.asset.get_by_guid(application.guid, asset_type=Application, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == application.guid @@ -176,7 +176,7 @@ def test_read_deleted_application( connection: Connection, application: Application, ): - deleted = client.asset.get_by_guid(application.guid, asset_type=Application) + deleted = client.asset.get_by_guid(application.guid, asset_type=Application, ignore_relationships=False) assert deleted assert deleted.guid == application.guid assert deleted.qualified_name == application.qualified_name @@ -198,6 +198,7 @@ def test_restore_application( restored = client.asset.get_by_qualified_name( asset_type=Application, qualified_name=application.qualified_name, + ignore_relationships=False ) assert restored assert restored.guid == application.guid diff --git a/tests/integration/azure_event_hub_asset_test.py b/tests/integration/azure_event_hub_asset_test.py index b76ed070..55900af5 100644 --- a/tests/integration/azure_event_hub_asset_test.py +++ b/tests/integration/azure_event_hub_asset_test.py @@ -145,7 +145,7 @@ def test_update_event_hub_assets( def _retrieve_event_hub_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type) + retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -191,7 +191,7 @@ def test_read_deleted_event_hub_consumer_group( consumer_group: AzureEventHubConsumerGroup, ): deleted = client.asset.get_by_guid( - consumer_group.guid, asset_type=AzureEventHubConsumerGroup + consumer_group.guid, asset_type=AzureEventHubConsumerGroup, ignore_relationships=False ) assert deleted assert deleted.status == EntityStatus.DELETED @@ -213,6 +213,7 @@ def test_restore_event_hub_consumer_group( restored = client.asset.get_by_qualified_name( asset_type=AzureEventHubConsumerGroup, qualified_name=consumer_group.qualified_name, + ignore_relationships=False ) assert restored assert restored.guid == consumer_group.guid diff --git a/tests/integration/connection_test.py b/tests/integration/connection_test.py index c4d5309d..7e779a8d 100644 --- a/tests/integration/connection_test.py +++ b/tests/integration/connection_test.py @@ -20,7 +20,7 @@ def create_connection( ) response = client.asset.save(to_create) result = response.assets_created(asset_type=Connection)[0] - return client.asset.get_by_guid(result.guid, asset_type=Connection) + return client.asset.get_by_guid(result.guid, asset_type=Connection, ignore_relationships=False) def test_invalid_connection(client: AtlanClient): diff --git a/tests/integration/custom_metadata_test.py b/tests/integration/custom_metadata_test.py index cfe91d25..ebf5eedb 100644 --- a/tests/integration/custom_metadata_test.py +++ b/tests/integration/custom_metadata_test.py @@ -882,7 +882,7 @@ def test_update_replacing_cm( assert t.qualified_name == term.qualified_name assert term.qualified_name x = client.asset.get_by_qualified_name( - qualified_name=term.qualified_name, asset_type=AtlasGlossaryTerm + qualified_name=term.qualified_name, asset_type=AtlasGlossaryTerm, ignore_relationships=False ) assert x assert not x.is_incomplete diff --git a/tests/integration/data_mesh_test.py b/tests/integration/data_mesh_test.py index 268e836c..65bb1a04 100644 --- a/tests/integration/data_mesh_test.py +++ b/tests/integration/data_mesh_test.py @@ -141,7 +141,7 @@ def test_update_domain(client: AtlanClient, domain: DataDomain): @pytest.mark.order(after="test_update_domain") def test_retrieve_domain(client: AtlanClient, domain: DataDomain): - test_domain = client.asset.get_by_guid(domain.guid, asset_type=DataDomain) + test_domain = client.asset.get_by_guid(domain.guid, asset_type=DataDomain, ignore_relationships=False) assert test_domain assert test_domain.guid == domain.guid assert test_domain.qualified_name == domain.qualified_name @@ -193,7 +193,7 @@ def test_update_sub_domain(client: AtlanClient, sub_domain: DataDomain): @pytest.mark.order(after="test_update_sub_domain") def test_retrieve_sub_domain(client: AtlanClient, sub_domain: DataDomain): - test_sub_domain = client.asset.get_by_guid(sub_domain.guid, asset_type=DataDomain) + test_sub_domain = client.asset.get_by_guid(sub_domain.guid, asset_type=DataDomain, ignore_relationships=False) assert test_sub_domain assert test_sub_domain.guid == sub_domain.guid assert test_sub_domain.qualified_name == sub_domain.qualified_name @@ -339,12 +339,12 @@ def test_contract( client: AtlanClient, table: Table, product: DataProduct, contract: DataContract ): assert product and product.guid - product = client.asset.get_by_guid(guid=product.guid, asset_type=DataProduct) + product = client.asset.get_by_guid(guid=product.guid, asset_type=DataProduct, ignore_relationships=False) assert product and product.output_ports and len(product.output_ports) table_asset = product.output_ports[0] assert table and table.guid assert table.guid == table_asset.guid - table = client.asset.get_by_guid(guid=table_asset.guid, asset_type=Table) + table = client.asset.get_by_guid(guid=table_asset.guid, asset_type=Table, ignore_relationships=False) assert table.has_contract assert table.data_contract_latest table_data_contract = table.data_contract_latest @@ -360,7 +360,7 @@ def test_update_contract( client: AtlanClient, table: Table, updated_contract: DataContract ): assert table and table.guid - table = client.asset.get_by_guid(guid=table.guid, asset_type=Table) + table = client.asset.get_by_guid(guid=table.guid, asset_type=Table, ignore_relationships=False) assert table.has_contract assert table.data_contract_latest table_data_contract = table.data_contract_latest @@ -436,7 +436,7 @@ def test_update_product( @pytest.mark.order(after="test_update_product") def test_retrieve_product(client: AtlanClient, product: DataProduct): - test_product = client.asset.get_by_guid(product.guid, asset_type=DataProduct) + test_product = client.asset.get_by_guid(product.guid, asset_type=DataProduct, ignore_relationships=False) assert test_product assert test_product.guid == product.guid assert test_product.qualified_name == product.qualified_name @@ -450,7 +450,7 @@ def test_retrieve_contract( client: AtlanClient, table: Table, updated_contract: DataContract ): test_contract = client.asset.get_by_guid( - updated_contract.guid, asset_type=DataContract + updated_contract.guid, asset_type=DataContract, ignore_relationships=False ) assert test_contract assert test_contract.name == updated_contract.name diff --git a/tests/integration/data_studio_asset_test.py b/tests/integration/data_studio_asset_test.py index a3bf0f50..d6ad073f 100644 --- a/tests/integration/data_studio_asset_test.py +++ b/tests/integration/data_studio_asset_test.py @@ -192,7 +192,7 @@ def test_retrieve_data_studio_asset_data_source( data_studio_asset_data_source: DataStudioAsset, ): b = client.asset.get_by_guid( - data_studio_asset_data_source.guid, asset_type=DataStudioAsset + data_studio_asset_data_source.guid, asset_type=DataStudioAsset, ignore_relationships=False ) assert b assert not b.is_incomplete @@ -261,7 +261,7 @@ def test_read_deleted_data_studio_asset_data_source( data_studio_asset_data_source: DataStudioAsset, ): deleted = client.asset.get_by_guid( - data_studio_asset_data_source.guid, asset_type=DataStudioAsset + data_studio_asset_data_source.guid, asset_type=DataStudioAsset, ignore_relationships=False ) assert deleted assert deleted.guid == data_studio_asset_data_source.guid @@ -283,7 +283,7 @@ def test_restore_data_studio_asset_data_source( assert data_studio_asset_data_source.qualified_name restored = client.asset.get_by_qualified_name( asset_type=DataStudioAsset, - qualified_name=data_studio_asset_data_source.qualified_name, + qualified_name=data_studio_asset_data_source.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == data_studio_asset_data_source.guid diff --git a/tests/integration/file_test.py b/tests/integration/file_test.py index 75992a4d..637cca66 100644 --- a/tests/integration/file_test.py +++ b/tests/integration/file_test.py @@ -112,7 +112,7 @@ def test_read_file( connection: Connection, file: File, ): - r = client.asset.get_by_guid(file.guid, asset_type=File) + r = client.asset.get_by_guid(file.guid, asset_type=File, ignore_relationships=False) assert r assert r.guid == file.guid assert r.qualified_name == file.qualified_name diff --git a/tests/integration/gcs_asset_test.py b/tests/integration/gcs_asset_test.py index db0f0401..0554d3a0 100644 --- a/tests/integration/gcs_asset_test.py +++ b/tests/integration/gcs_asset_test.py @@ -164,7 +164,7 @@ def test_retrieve_gcs_object( gcs_bucket: GCSBucket, gcs_object: GCSObject, ): - b = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject) + b = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == gcs_object.guid @@ -235,7 +235,7 @@ def test_read_deleted_gcs_object( gcs_bucket: GCSBucket, gcs_object: GCSObject, ): - deleted = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject) + deleted = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject, ignore_relationships=False) assert deleted assert deleted.guid == gcs_object.guid assert deleted.qualified_name == gcs_object.qualified_name @@ -255,7 +255,7 @@ def test_restore_object( ) assert gcs_object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=GCSObject, qualified_name=gcs_object.qualified_name + asset_type=GCSObject, qualified_name=gcs_object.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == gcs_object.guid diff --git a/tests/integration/glossary_test.py b/tests/integration/glossary_test.py index 74301c7a..47af760c 100644 --- a/tests/integration/glossary_test.py +++ b/tests/integration/glossary_test.py @@ -270,7 +270,7 @@ def test_category( assert category.guid assert category.name == MODULE_NAME assert category.qualified_name - c = client.asset.get_by_guid(category.guid, AtlasGlossaryCategory) + c = client.asset.get_by_guid(category.guid, AtlasGlossaryCategory, ignore_relationships=False) assert c assert c.guid == category.guid assert c.anchor @@ -311,7 +311,7 @@ def test_term1( assert term1.name == TERM_NAME1 assert term1.qualified_name assert term1.qualified_name != TERM_NAME1 - t = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm) + t = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert t assert t.guid == term1.guid assert t.attributes.anchor @@ -336,7 +336,7 @@ def test_term2( assert term2.name == TERM_NAME2 assert term2.qualified_name assert term2.qualified_name != TERM_NAME2 - t = client.asset.get_by_guid(term2.guid, asset_type=AtlasGlossaryTerm) + t = client.asset.get_by_guid(term2.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert t assert t.guid == term2.guid assert t.attributes.anchor @@ -361,7 +361,7 @@ def test_term3( assert term3.name == TERM_NAME3 assert term3.qualified_name assert term3.qualified_name != TERM_NAME3 - t = client.asset.get_by_guid(term3.guid, asset_type=AtlasGlossaryTerm) + t = client.asset.get_by_guid(term3.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert t assert t.guid == term3.guid assert t.attributes.anchor @@ -386,7 +386,7 @@ def test_term4( assert term4.name == TERM_NAME4 assert term4.qualified_name assert term4.qualified_name != TERM_NAME4 - t = client.asset.get_by_guid(term4.guid, asset_type=AtlasGlossaryTerm) + t = client.asset.get_by_guid(term4.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert t assert t.guid == term4.guid assert t.attributes.anchor @@ -401,7 +401,7 @@ def test_read_glossary( term3: AtlasGlossaryTerm, term4: AtlasGlossaryTerm, ): - g = client.asset.get_by_guid(glossary.guid, asset_type=AtlasGlossary) + g = client.asset.get_by_guid(glossary.guid, asset_type=AtlasGlossary, ignore_relationships=False) assert g assert isinstance(g, AtlasGlossary) assert g.guid == glossary.guid @@ -540,7 +540,7 @@ def test_term_trim_to_required( client: AtlanClient, term1: AtlasGlossaryTerm, ): - term1 = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm) + term1 = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) term1 = term1.trim_to_required() response = client.asset.save(term1) assert response.mutated_entities is None @@ -801,7 +801,7 @@ def test_create_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm) + result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert result assert result.see_also assert len(result.see_also) == 2 @@ -836,7 +836,7 @@ def test_remove_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm) + result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert result assert result.see_also active_relationships = [] @@ -871,7 +871,7 @@ def test_append_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm) + result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert result assert result.see_also active_relationships = [] @@ -907,7 +907,7 @@ def test_append_relationship_again( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm) + result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert result assert result.see_also active_relationships = [] diff --git a/tests/integration/kafka_asset_test.py b/tests/integration/kafka_asset_test.py index 30384af6..b4288bf4 100644 --- a/tests/integration/kafka_asset_test.py +++ b/tests/integration/kafka_asset_test.py @@ -143,7 +143,7 @@ def test_update_kafka_assets( def _retrieve_kafka_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type) + retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -189,7 +189,7 @@ def test_read_deleted_kafka_consumer_group( consumer_group: KafkaConsumerGroup, ): deleted = client.asset.get_by_guid( - consumer_group.guid, asset_type=KafkaConsumerGroup + consumer_group.guid, asset_type=KafkaConsumerGroup, ignore_relationships=False ) assert deleted assert deleted.status == EntityStatus.DELETED @@ -208,7 +208,7 @@ def test_restore_kafka_consumer_group( ) assert consumer_group.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=KafkaConsumerGroup, qualified_name=consumer_group.qualified_name + asset_type=KafkaConsumerGroup, qualified_name=consumer_group.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == consumer_group.guid diff --git a/tests/integration/lineage_test.py b/tests/integration/lineage_test.py index 2eb2b043..d74a2bae 100644 --- a/tests/integration/lineage_test.py +++ b/tests/integration/lineage_test.py @@ -701,13 +701,13 @@ def test_restore_lineage( ) to_restore.status = EntityStatus.ACTIVE client.asset.save(to_restore) - restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process) + restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process, ignore_relationships=False) assert restored count = 0 # TODO: replace with exponential back-off and jitter while restored.status == EntityStatus.DELETED: time.sleep(2) - restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process) + restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process, ignore_relationships=False) count += 1 assert restored.guid == lineage_start.guid assert restored.qualified_name == lineage_start.qualified_name diff --git a/tests/integration/persona_test.py b/tests/integration/persona_test.py index 9d52e754..aa40e354 100644 --- a/tests/integration/persona_test.py +++ b/tests/integration/persona_test.py @@ -170,7 +170,7 @@ def test_retrieve_persona( ): assert persona.qualified_name one = client.asset.get_by_qualified_name( - qualified_name=persona.qualified_name, asset_type=Persona + qualified_name=persona.qualified_name, asset_type=Persona, ignore_relationships=False ) assert one assert one.guid == persona.guid @@ -187,7 +187,7 @@ def test_retrieve_persona( for policy in policies: # Need to retrieve the full policy if we want to see any info about it # (what comes back on the Persona itself are just policy references) - full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy) + full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False) assert full sub_cat = full.policy_sub_category assert sub_cat diff --git a/tests/integration/preset_asset_test.py b/tests/integration/preset_asset_test.py index 0e87d654..35e0a82e 100644 --- a/tests/integration/preset_asset_test.py +++ b/tests/integration/preset_asset_test.py @@ -335,7 +335,7 @@ def test_retrieve_preset_dashboard( client: AtlanClient, preset_dashboard: PresetDashboard, ): - b = client.asset.get_by_guid(preset_dashboard.guid, asset_type=PresetDashboard) + b = client.asset.get_by_guid(preset_dashboard.guid, asset_type=PresetDashboard, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == preset_dashboard.guid @@ -404,7 +404,7 @@ def test_restore_dashboard( ) assert preset_dashboard.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=PresetDashboard, qualified_name=preset_dashboard.qualified_name + asset_type=PresetDashboard, qualified_name=preset_dashboard.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == preset_dashboard.guid diff --git a/tests/integration/purpose_test.py b/tests/integration/purpose_test.py index 22ca826f..00ee6a78 100644 --- a/tests/integration/purpose_test.py +++ b/tests/integration/purpose_test.py @@ -133,7 +133,7 @@ def test_purpose(client: AtlanClient, purpose: Purpose, atlan_tag_name: AtlanTag assert purpose.name == MODULE_NAME assert purpose.display_name == MODULE_NAME assert purpose.qualified_name != MODULE_NAME - purpose = client.asset.get_by_guid(guid=purpose.guid, asset_type=Purpose) + purpose = client.asset.get_by_guid(guid=purpose.guid, asset_type=Purpose, ignore_relationships=False) assert purpose.purpose_atlan_tags assert [atlan_tag_name] == purpose.purpose_atlan_tags @@ -226,7 +226,7 @@ def test_retrieve_purpose( ): assert purpose.qualified_name one = client.asset.get_by_qualified_name( - qualified_name=purpose.qualified_name, asset_type=Purpose + qualified_name=purpose.qualified_name, asset_type=Purpose, ignore_relationships=False ) assert one assert one.guid == purpose.guid @@ -244,7 +244,7 @@ def test_retrieve_purpose( for policy in policies: # Need to retrieve the full policy if we want to see any info about it # (what comes back on the Persona itself are just policy references) - full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy) + full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False) assert full sub_cat = full.policy_sub_category assert sub_cat diff --git a/tests/integration/s3_asset_test.py b/tests/integration/s3_asset_test.py index 1ae2b946..a548356b 100644 --- a/tests/integration/s3_asset_test.py +++ b/tests/integration/s3_asset_test.py @@ -181,7 +181,7 @@ def _assert_update_bucket(client, bucket, with_name=False): def _assert_retrieve_bucket(client, bucket, s3object, with_name=False): - b = client.asset.get_by_guid(bucket.guid, asset_type=S3Bucket) + b = client.asset.get_by_guid(bucket.guid, asset_type=S3Bucket, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == bucket.guid @@ -244,7 +244,7 @@ def _assert_delete_object(client, s3object): def _assert_read_delete_object(client, s3object): - deleted = client.asset.get_by_guid(s3object.guid, asset_type=S3Object) + deleted = client.asset.get_by_guid(s3object.guid, asset_type=S3Object, ignore_relationships=False) assert deleted assert deleted.guid == s3object.guid assert deleted.qualified_name == s3object.qualified_name @@ -258,7 +258,7 @@ def _assert_restore_object(client, s3object): ) assert s3object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=S3Object, qualified_name=s3object.qualified_name + asset_type=S3Object, qualified_name=s3object.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == s3object.guid diff --git a/tests/integration/superset_asset_test.py b/tests/integration/superset_asset_test.py index cb51fb98..049e72dd 100644 --- a/tests/integration/superset_asset_test.py +++ b/tests/integration/superset_asset_test.py @@ -274,7 +274,7 @@ def test_retrieve_superset_dashboard( client: AtlanClient, superset_dashboard: SupersetDashboard, ): - b = client.asset.get_by_guid(superset_dashboard.guid, asset_type=SupersetDashboard) + b = client.asset.get_by_guid(superset_dashboard.guid, asset_type=SupersetDashboard, ignore_relationships=False) assert b assert not b.is_incomplete assert b.guid == superset_dashboard.guid @@ -343,7 +343,7 @@ def test_restore_dashboard( ) assert superset_dashboard.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=SupersetDashboard, qualified_name=superset_dashboard.qualified_name + asset_type=SupersetDashboard, qualified_name=superset_dashboard.qualified_name, ignore_relationships=False ) assert restored assert restored.guid == superset_dashboard.guid diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index 9833b246..7837e3c0 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -144,7 +144,7 @@ def _test_update_certificate( assert test_asset.qualified_name assert test_asset.name test_asset = client.asset.get_by_guid( - guid=test_asset.guid, asset_type=test_asset_type + guid=test_asset.guid, asset_type=test_asset_type, ignore_relationships=False ) assert test_asset.qualified_name assert test_asset.name @@ -160,7 +160,7 @@ def _test_update_certificate( glossary_guid=glossary_guid if glossary_guid else None, ) test_asset = client.asset.get_by_guid( - guid=test_asset.guid, asset_type=test_asset_type + guid=test_asset.guid, asset_type=test_asset_type, ignore_relationships=False ) assert test_asset.certificate_status == CertificateStatus.DRAFT assert test_asset.certificate_status_message == message @@ -181,7 +181,7 @@ def _test_remove_certificate( glossary_guid=glossary_guid if glossary_guid else None, ) test_asset = client.asset.get_by_guid( - guid=test_asset.guid, asset_type=test_asset_type + guid=test_asset.guid, asset_type=test_asset_type, ignore_relationships=False ) assert test_asset.certificate_status is None assert test_asset.certificate_status_message is None @@ -204,7 +204,7 @@ def _test_update_announcement( glossary_guid=glossary_guid if glossary_guid else None, ) test_asset = client.asset.get_by_guid( - guid=test_asset.guid, asset_type=test_asset_type + guid=test_asset.guid, asset_type=test_asset_type, ignore_relationships=False ) assert test_asset.get_announcment() == test_announcement @@ -224,7 +224,7 @@ def _test_remove_announcement( glossary_guid=glossary_guid if glossary_guid else None, ) test_asset = client.asset.get_by_guid( - guid=test_asset.guid, asset_type=test_asset_type + guid=test_asset.guid, asset_type=test_asset_type, ignore_relationships=False ) assert test_asset.get_announcment() is None @@ -237,7 +237,7 @@ def test_append_terms_with_guid( guid=database.guid, asset_type=Database, terms=[term1] ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -253,7 +253,7 @@ def test_append_terms_with_qualified_name( qualified_name=database.qualified_name, asset_type=Database, terms=[term1] ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -271,7 +271,7 @@ def test_append_terms_using_ref_by_guid_for_term( terms=[AtlasGlossaryTerm.ref_by_guid(guid=term1.guid)], ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -297,7 +297,7 @@ def test_replace_a_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) assert database.assigned_terms assert len(database.assigned_terms) == 2 deleted_terms = [ @@ -331,7 +331,7 @@ def test_replace_all_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) assert database.assigned_terms assert len(database.assigned_terms) == 1 deleted_terms = [ @@ -366,7 +366,7 @@ def test_remove_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database) + database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships= False) assert database.assigned_terms assert len(database.assigned_terms) == 2 deleted_terms = [ @@ -391,14 +391,14 @@ def test_find_connections_by_name(client: AtlanClient): def test_get_asset_by_guid_good_guid(client: AtlanClient, glossary: AtlasGlossary): - glossary = client.asset.get_by_guid(glossary.guid, AtlasGlossary) + glossary = client.asset.get_by_guid(glossary.guid, AtlasGlossary, ignore_relationships=False) assert isinstance(glossary, AtlasGlossary) def test_get_asset_by_guid_without_asset_type( client: AtlanClient, glossary: AtlasGlossary ): - glossary = client.asset.get_by_guid(glossary.guid) + glossary = client.asset.get_by_guid(glossary.guid, ignore_relationships=False) assert isinstance(glossary, AtlasGlossary) @@ -417,7 +417,7 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not NotFoundError, match=f"ATLAN-PYTHON-404-002 Asset with GUID {guid} is not of the type requested: Table.", ): - client.asset.get_by_guid(guid, Table) + client.asset.get_by_guid(guid, Table, ignore_relationships=False) def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error( @@ -428,7 +428,7 @@ def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error( 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) + client.asset.get_by_guid("76d54dd6", AtlasGlossary, ignore_relationships=False) def test_upsert_when_no_changes(client: AtlanClient, glossary: AtlasGlossary): @@ -463,7 +463,7 @@ def test_add_classification(client: AtlanClient, term1: AtlasGlossaryTerm): client.asset.add_atlan_tags( AtlasGlossaryTerm, term1.qualified_name, [CLASSIFICATION_NAME] ) - glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm) + glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert glossary_term.atlan_tags assert len(glossary_term.atlan_tags) == 1 classification = glossary_term.atlan_tags[0] @@ -504,7 +504,7 @@ def test_remove_classification(client: AtlanClient, term1: AtlasGlossaryTerm): client.asset.remove_atlan_tag( AtlasGlossaryTerm, term1.qualified_name, CLASSIFICATION_NAME ) - glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm) + glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) assert not glossary_term.atlan_tags diff --git a/tests/integration/test_index_search.py b/tests/integration/test_index_search.py index 2aa9d7b0..cc3a57af 100644 --- a/tests/integration/test_index_search.py +++ b/tests/integration/test_index_search.py @@ -184,7 +184,7 @@ def test_search_source_synced_assets(client: AtlanClient): def test_source_tag_assign_with_value(client: AtlanClient, table: Table): # Make sure no tags are assigned initially assert table.guid - table = client.asset.get_by_guid(guid=table.guid, asset_type=Table) + table = client.asset.get_by_guid(guid=table.guid, asset_type=Table, ignore_relationships=False) assert not table.atlan_tags assert table.name and table.qualified_name diff --git a/tests/integration/test_sql_assets.py b/tests/integration/test_sql_assets.py index 0cd638b0..d7e1039a 100644 --- a/tests/integration/test_sql_assets.py +++ b/tests/integration/test_sql_assets.py @@ -91,7 +91,7 @@ def test_create( assert response.guid_assignments assert c.guid in response.guid_assignments c = response.mutated_entities.CREATE[0] - c = client.asset.get_by_guid(c.guid, Connection) + c = client.asset.get_by_guid(c.guid, Connection, ignore_relationships=False) assert isinstance(c, Connection) TestConnection.connection = c @@ -148,7 +148,7 @@ def test_create( assert response.guid_assignments assert database.guid in response.guid_assignments database = response.mutated_entities.CREATE[0] - client.asset.get_by_guid(database.guid, Database) + client.asset.get_by_guid(database.guid, Database, ignore_relationships=False) TestDatabase.database = database @pytest.mark.order(after="test_create") @@ -196,10 +196,10 @@ def test_create( response = upsert(schema) assert (schemas := response.assets_created(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(schemas[0].guid, Schema) + schema = client.asset.get_by_guid(schemas[0].guid, Schema, ignore_relationships=False) assert (databases := response.assets_updated(asset_type=Database)) assert len(databases) == 1 - database = client.asset.get_by_guid(databases[0].guid, Database) + database = client.asset.get_by_guid(databases[0].guid, Database, ignore_relationships=False) assert database.attributes.schemas schemas = database.attributes.schemas assert len(schemas) == 1 @@ -227,10 +227,10 @@ def test_overload_creator( response = upsert(schema) assert (schemas := response.assets_created(asset_type=Schema)) assert len(schemas) == 1 - overload_schema = client.asset.get_by_guid(schemas[0].guid, Schema) + overload_schema = client.asset.get_by_guid(schemas[0].guid, Schema, ignore_relationships=False) assert (databases := response.assets_updated(asset_type=Database)) assert len(databases) == 1 - database = client.asset.get_by_guid(databases[0].guid, Database) + database = client.asset.get_by_guid(databases[0].guid, Database, ignore_relationships=False) assert database.attributes.schemas schemas = database.attributes.schemas assert len(schemas) == 2 @@ -299,10 +299,10 @@ def test_create( response = upsert(table) assert (tables := response.assets_created(asset_type=Table)) assert len(tables) == 1 - table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table) + table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table, ignore_relationships=False) assert (schemas := response.assets_updated(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema) + schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False) assert schema.attributes.tables tables = schema.attributes.tables assert len(tables) == 1 @@ -335,10 +335,10 @@ def test_overload_creator( response = upsert(table) assert (tables := response.assets_created(asset_type=Table)) assert len(tables) == 1 - overload_table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table) + overload_table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table, ignore_relationships=False) assert (schemas := response.assets_updated(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema) + schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False) assert schema.attributes.tables tables = schema.attributes.tables assert len(tables) == 2 @@ -395,7 +395,7 @@ def test_source_read_recent_user_record_list_readable( popularity_insight: PopularityInsights, ): assert TestTable.table - asset = client.asset.get_by_guid(guid=TestTable.table.guid, asset_type=Table) + asset = client.asset.get_by_guid(guid=TestTable.table.guid, asset_type=Table, ignore_relationships=False) assert asset.source_read_recent_user_record_list asset_popularity = asset.source_read_recent_user_record_list[0] self.verify_popularity(asset_popularity, popularity_insight) @@ -551,8 +551,8 @@ def test_create( response = client.asset.save(column) assert (columns := response.assets_created(asset_type=Column)) assert len(columns) == 1 - column = client.asset.get_by_guid(asset_type=Column, guid=columns[0].guid) - table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid) + column = client.asset.get_by_guid(asset_type=Column, guid=columns[0].guid, ignore_relationships=False) + table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False) assert table.attributes.columns columns = table.attributes.columns assert len(columns) == 1 @@ -624,9 +624,9 @@ def test_overload_creator( assert (columns := response.assets_created(asset_type=Column)) assert len(columns) == 1 overload_column = client.asset.get_by_guid( - asset_type=Column, guid=columns[0].guid + asset_type=Column, guid=columns[0].guid, ignore_relationships=False ) - table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid) + table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False) assert table.attributes.columns columns = table.attributes.columns @@ -692,7 +692,7 @@ def test_create( assert len(reaadmes) == 1 assert (columns := response.assets_updated(asset_type=Column)) assert len(columns) == 1 - readme = client.asset.get_by_guid(guid=reaadmes[0].guid, asset_type=Readme) + readme = client.asset.get_by_guid(guid=reaadmes[0].guid, asset_type=Readme, ignore_relationships=False) assert readme.description == self.CONTENT TestReadme.readme = readme diff --git a/tests/integration/test_task_client.py b/tests/integration/test_task_client.py index 2eebe10d..8e81b1ba 100644 --- a/tests/integration/test_task_client.py +++ b/tests/integration/test_task_client.py @@ -46,7 +46,7 @@ def snowflake_column( restrict_lineage_propagation=True, ) snowflake_column = client.asset.get_by_qualified_name( - snowflake_column_qn, asset_type=Column + snowflake_column_qn, asset_type=Column, ignore_relationships=False ) yield snowflake_column diff --git a/tests/integration/utils.py b/tests/integration/utils.py index 1780403b..f30c7e08 100644 --- a/tests/integration/utils.py +++ b/tests/integration/utils.py @@ -33,7 +33,7 @@ def retrieve_and_check_assets( leftovers = [] for one in to_check: try: - candidate = client.asset.get_by_guid(one.guid, asset_type=type(one)) + candidate = client.asset.get_by_guid(one.guid, asset_type=type(one), ignore_relationships=False) if candidate and candidate.status == EntityStatus.ACTIVE: leftovers.append(candidate) except NotFoundError: diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 40d36ce7..62c7f319 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1555,7 +1555,7 @@ def test_asset_get_by_guid_without_asset_type(mock_api_caller, get_by_guid_json) client = AssetClient(mock_api_caller) mock_api_caller._call_api.side_effect = [get_by_guid_json] - response = client.get_by_guid(guid="test-table-guid-123") + response = client.get_by_guid(guid="test-table-guid-123", ignore_relationships=False) assert response assert isinstance(response, Table) From 604cd7dad43f1003b9c3202d87d3cf7bb27c8ba5 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 14:39:42 +0530 Subject: [PATCH 05/66] Fixed qa checks --- pyatlan/client/asset.py | 20 +++++-- pyatlan/samples/events/lambda_scorer.py | 4 +- pyatlan/test_utils/__init__.py | 4 +- tests/integration/adls_asset_test.py | 12 +++-- tests/integration/airflow_asset_test.py | 12 +++-- tests/integration/api_asset_test.py | 47 ++++++++++++----- tests/integration/app_asset_test.py | 10 ++-- .../integration/azure_event_hub_asset_test.py | 10 ++-- tests/integration/connection_test.py | 4 +- tests/integration/custom_metadata_test.py | 4 +- tests/integration/data_mesh_test.py | 24 ++++++--- tests/integration/data_studio_asset_test.py | 11 ++-- tests/integration/gcs_asset_test.py | 12 +++-- tests/integration/glossary_test.py | 44 ++++++++++++---- tests/integration/kafka_asset_test.py | 8 ++- tests/integration/lineage_test.py | 8 ++- tests/integration/persona_test.py | 8 ++- tests/integration/preset_asset_test.py | 8 ++- tests/integration/purpose_test.py | 12 +++-- tests/integration/s3_asset_test.py | 12 +++-- tests/integration/superset_asset_test.py | 10 +++- tests/integration/test_client.py | 36 +++++++++---- tests/integration/test_index_search.py | 4 +- tests/integration/test_sql_assets.py | 52 ++++++++++++++----- tests/integration/utils.py | 4 +- tests/unit/test_client.py | 4 +- 26 files changed, 287 insertions(+), 97 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index b1980ef5..a6cd8f8d 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -814,7 +814,9 @@ def _restore(self, asset_type: Type[A], qualified_name: str, retries: int) -> bo if not asset_type.can_be_archived(): return False existing = self.get_by_qualified_name( - asset_type=asset_type, qualified_name=qualified_name, ignore_relationships=False + asset_type=asset_type, + qualified_name=qualified_name, + ignore_relationships=False, ) if not existing: # Nothing to restore, so cannot be restored @@ -1379,10 +1381,14 @@ def replace_terms( if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid(guid=guid, asset_type=asset_type, ignore_relationships=False) + asset = self.get_by_guid( + guid=guid, asset_type=asset_type, ignore_relationships=False + ) elif qualified_name: asset = self.get_by_qualified_name( - qualified_name=qualified_name, asset_type=asset_type, ignore_relationships=False + qualified_name=qualified_name, + asset_type=asset_type, + ignore_relationships=False, ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() @@ -1417,10 +1423,14 @@ def remove_terms( if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid(guid=guid, asset_type=asset_type, ignore_relationships=False) + asset = self.get_by_guid( + guid=guid, asset_type=asset_type, ignore_relationships=False + ) elif qualified_name: asset = self.get_by_qualified_name( - qualified_name=qualified_name, asset_type=asset_type, ignore_relationships=False + qualified_name=qualified_name, + asset_type=asset_type, + ignore_relationships=False, ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() diff --git a/pyatlan/samples/events/lambda_scorer.py b/pyatlan/samples/events/lambda_scorer.py index b2f05c04..0a270b81 100644 --- a/pyatlan/samples/events/lambda_scorer.py +++ b/pyatlan/samples/events/lambda_scorer.py @@ -209,7 +209,9 @@ def calculate_changes(self, asset: Asset) -> List[Asset]: s_readme = 0 readme = asset.readme if readme and readme.guid: - readme = client.asset.get_by_guid(readme.guid, asset_type=Readme, ignore_relationships=False) + readme = client.asset.get_by_guid( + readme.guid, asset_type=Readme, ignore_relationships=False + ) if description := readme.description: if len(description) > 1000: s_readme = 20 diff --git a/pyatlan/test_utils/__init__.py b/pyatlan/test_utils/__init__.py index 38f840af..f040d858 100644 --- a/pyatlan/test_utils/__init__.py +++ b/pyatlan/test_utils/__init__.py @@ -112,7 +112,9 @@ def create_connection( ) response = client.asset.save(to_create) result = response.assets_created(asset_type=Connection)[0] - return client.asset.get_by_guid(result.guid, asset_type=Connection, ignore_relationships=False) + return client.asset.get_by_guid( + result.guid, asset_type=Connection, ignore_relationships=False + ) def create_group(client: AtlanClient, name: str) -> CreateGroupResponse: diff --git a/tests/integration/adls_asset_test.py b/tests/integration/adls_asset_test.py index 0859fe8a..76165e80 100644 --- a/tests/integration/adls_asset_test.py +++ b/tests/integration/adls_asset_test.py @@ -249,7 +249,9 @@ def test_retrieve_adls_object( adls_container: ADLSContainer, adls_object: ADLSObject, ): - b = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject, ignore_relationships=False) + b = client.asset.get_by_guid( + adls_object.guid, asset_type=ADLSObject, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == adls_object.guid @@ -319,7 +321,9 @@ def test_read_deleted_adls_object( adls_container: ADLSContainer, adls_object: ADLSObject, ): - deleted = client.asset.get_by_guid(adls_object.guid, asset_type=ADLSObject, ignore_relationships=False) + deleted = client.asset.get_by_guid( + adls_object.guid, asset_type=ADLSObject, ignore_relationships=False + ) assert deleted assert deleted.guid == adls_object.guid assert deleted.qualified_name == adls_object.qualified_name @@ -339,7 +343,9 @@ def test_restore_object( ) assert adls_object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=ADLSObject, qualified_name=adls_object.qualified_name, ignore_relationships=False + asset_type=ADLSObject, + qualified_name=adls_object.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == adls_object.guid diff --git a/tests/integration/airflow_asset_test.py b/tests/integration/airflow_asset_test.py index 7e1d1df0..a6608102 100644 --- a/tests/integration/airflow_asset_test.py +++ b/tests/integration/airflow_asset_test.py @@ -170,7 +170,9 @@ def test_update_airflow_assets( def _retrieve_airflow_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) + retrieved = client.asset.get_by_guid( + asset.guid, asset_type=asset_type, ignore_relationships=False + ) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -215,7 +217,9 @@ def test_read_deleted_airflow_task( client: AtlanClient, airflow_task: AirflowTask, ): - deleted = client.asset.get_by_guid(airflow_task.guid, asset_type=AirflowTask, ignore_relationships=False) + deleted = client.asset.get_by_guid( + airflow_task.guid, asset_type=AirflowTask, ignore_relationships=False + ) assert deleted assert deleted.status == EntityStatus.DELETED assert deleted.guid == airflow_task.guid @@ -233,7 +237,9 @@ def test_restore_airflow_task( ) assert airflow_task.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=AirflowTask, qualified_name=airflow_task.qualified_name, ignore_relationships=False + asset_type=AirflowTask, + qualified_name=airflow_task.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == airflow_task.guid diff --git a/tests/integration/api_asset_test.py b/tests/integration/api_asset_test.py index 7a586358..dd042a6b 100644 --- a/tests/integration/api_asset_test.py +++ b/tests/integration/api_asset_test.py @@ -187,7 +187,9 @@ def test_update_api_path( def test_retrieve_api_path( client: AtlanClient, connection: Connection, api_spec: APISpec, api_path: APIPath ): - b = client.asset.get_by_guid(api_path.guid, asset_type=APIPath, ignore_relationships=False) + b = client.asset.get_by_guid( + api_path.guid, asset_type=APIPath, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == api_path.guid @@ -250,7 +252,9 @@ def test_delete_api_path( def test_read_deleted_api_path( client: AtlanClient, connection: Connection, api_spec: APISpec, api_path: APIPath ): - deleted = client.asset.get_by_guid(api_path.guid, asset_type=APIPath, ignore_relationships=False) + deleted = client.asset.get_by_guid( + api_path.guid, asset_type=APIPath, ignore_relationships=False + ) assert deleted assert deleted.guid == api_path.guid assert deleted.qualified_name == api_path.qualified_name @@ -267,7 +271,9 @@ def test_restore_path( ) assert api_path.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIPath, qualified_name=api_path.qualified_name, ignore_relationships=False + asset_type=APIPath, + qualified_name=api_path.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == api_path.guid @@ -365,7 +371,9 @@ def test_update_api_object( def test_retrieve_api_object( client: AtlanClient, connection: Connection, api_object_overload: APIObject ): - b = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject, ignore_relationships=False) + b = client.asset.get_by_guid( + api_object_overload.guid, asset_type=APIObject, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == api_object_overload.guid @@ -398,7 +406,9 @@ def test_delete_api_object( def test_read_deleted_api_object( client: AtlanClient, connection: Connection, api_object_overload: APIObject ): - deleted = client.asset.get_by_guid(api_object_overload.guid, asset_type=APIObject, ignore_relationships=False) + deleted = client.asset.get_by_guid( + api_object_overload.guid, asset_type=APIObject, ignore_relationships=False + ) assert deleted assert deleted.guid == api_object_overload.guid assert deleted.qualified_name == api_object_overload.qualified_name @@ -415,7 +425,9 @@ def test_restore_object( ) assert api_object_overload.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIObject, qualified_name=api_object_overload.qualified_name, ignore_relationships=False + asset_type=APIObject, + qualified_name=api_object_overload.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == api_object_overload.guid @@ -597,7 +609,9 @@ def test_update_api_query( def test_retrieve_api_query( client: AtlanClient, connection: Connection, api_query_overload_3: APIQuery ): - b = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False) + b = client.asset.get_by_guid( + api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == api_query_overload_3.guid @@ -630,7 +644,9 @@ def test_delete_api_query( def test_read_deleted_api_query( client: AtlanClient, connection: Connection, api_query_overload_3: APIQuery ): - deleted = client.asset.get_by_guid(api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False) + deleted = client.asset.get_by_guid( + api_query_overload_3.guid, asset_type=APIQuery, ignore_relationships=False + ) assert deleted assert deleted.guid == api_query_overload_3.guid assert deleted.qualified_name == api_query_overload_3.qualified_name @@ -647,7 +663,9 @@ def test_restore_query( ) assert api_query_overload_3.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=APIQuery, qualified_name=api_query_overload_3.qualified_name, ignore_relationships=False + asset_type=APIQuery, + qualified_name=api_query_overload_3.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == api_query_overload_3.guid @@ -989,7 +1007,9 @@ def test_retrieve_api_field( api_field_parent_query_overload: APIField, ): b = client.asset.get_by_guid( - api_field_parent_query_overload.guid, asset_type=APIField, ignore_relationships=False + api_field_parent_query_overload.guid, + asset_type=APIField, + ignore_relationships=False, ) assert b assert not b.is_incomplete @@ -1031,7 +1051,9 @@ def test_read_deleted_api_field( api_field_parent_query_overload: APIField, ): deleted = client.asset.get_by_guid( - api_field_parent_query_overload.guid, asset_type=APIField, ignore_relationships=False + api_field_parent_query_overload.guid, + asset_type=APIField, + ignore_relationships=False, ) assert deleted assert deleted.guid == api_field_parent_query_overload.guid @@ -1053,7 +1075,8 @@ def test_restore_field( assert api_field_parent_query_overload.qualified_name restored = client.asset.get_by_qualified_name( asset_type=APIField, - qualified_name=api_field_parent_query_overload.qualified_name, ignore_relationships=False + qualified_name=api_field_parent_query_overload.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == api_field_parent_query_overload.guid diff --git a/tests/integration/app_asset_test.py b/tests/integration/app_asset_test.py index b7ca00a8..7d7f9b60 100644 --- a/tests/integration/app_asset_test.py +++ b/tests/integration/app_asset_test.py @@ -108,7 +108,9 @@ def test_retrieve_application( connection: Connection, application: Application, ): - b = client.asset.get_by_guid(application.guid, asset_type=Application, ignore_relationships=False) + b = client.asset.get_by_guid( + application.guid, asset_type=Application, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == application.guid @@ -176,7 +178,9 @@ def test_read_deleted_application( connection: Connection, application: Application, ): - deleted = client.asset.get_by_guid(application.guid, asset_type=Application, ignore_relationships=False) + deleted = client.asset.get_by_guid( + application.guid, asset_type=Application, ignore_relationships=False + ) assert deleted assert deleted.guid == application.guid assert deleted.qualified_name == application.qualified_name @@ -198,7 +202,7 @@ def test_restore_application( restored = client.asset.get_by_qualified_name( asset_type=Application, qualified_name=application.qualified_name, - ignore_relationships=False + ignore_relationships=False, ) assert restored assert restored.guid == application.guid diff --git a/tests/integration/azure_event_hub_asset_test.py b/tests/integration/azure_event_hub_asset_test.py index 55900af5..04dc7b34 100644 --- a/tests/integration/azure_event_hub_asset_test.py +++ b/tests/integration/azure_event_hub_asset_test.py @@ -145,7 +145,9 @@ def test_update_event_hub_assets( def _retrieve_event_hub_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) + retrieved = client.asset.get_by_guid( + asset.guid, asset_type=asset_type, ignore_relationships=False + ) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -191,7 +193,9 @@ def test_read_deleted_event_hub_consumer_group( consumer_group: AzureEventHubConsumerGroup, ): deleted = client.asset.get_by_guid( - consumer_group.guid, asset_type=AzureEventHubConsumerGroup, ignore_relationships=False + consumer_group.guid, + asset_type=AzureEventHubConsumerGroup, + ignore_relationships=False, ) assert deleted assert deleted.status == EntityStatus.DELETED @@ -213,7 +217,7 @@ def test_restore_event_hub_consumer_group( restored = client.asset.get_by_qualified_name( asset_type=AzureEventHubConsumerGroup, qualified_name=consumer_group.qualified_name, - ignore_relationships=False + ignore_relationships=False, ) assert restored assert restored.guid == consumer_group.guid diff --git a/tests/integration/connection_test.py b/tests/integration/connection_test.py index 7e779a8d..ea79e1e5 100644 --- a/tests/integration/connection_test.py +++ b/tests/integration/connection_test.py @@ -20,7 +20,9 @@ def create_connection( ) response = client.asset.save(to_create) result = response.assets_created(asset_type=Connection)[0] - return client.asset.get_by_guid(result.guid, asset_type=Connection, ignore_relationships=False) + return client.asset.get_by_guid( + result.guid, asset_type=Connection, ignore_relationships=False + ) def test_invalid_connection(client: AtlanClient): diff --git a/tests/integration/custom_metadata_test.py b/tests/integration/custom_metadata_test.py index ebf5eedb..9fa5ff51 100644 --- a/tests/integration/custom_metadata_test.py +++ b/tests/integration/custom_metadata_test.py @@ -882,7 +882,9 @@ def test_update_replacing_cm( assert t.qualified_name == term.qualified_name assert term.qualified_name x = client.asset.get_by_qualified_name( - qualified_name=term.qualified_name, asset_type=AtlasGlossaryTerm, ignore_relationships=False + qualified_name=term.qualified_name, + asset_type=AtlasGlossaryTerm, + ignore_relationships=False, ) assert x assert not x.is_incomplete diff --git a/tests/integration/data_mesh_test.py b/tests/integration/data_mesh_test.py index 65bb1a04..2c2dabb4 100644 --- a/tests/integration/data_mesh_test.py +++ b/tests/integration/data_mesh_test.py @@ -141,7 +141,9 @@ def test_update_domain(client: AtlanClient, domain: DataDomain): @pytest.mark.order(after="test_update_domain") def test_retrieve_domain(client: AtlanClient, domain: DataDomain): - test_domain = client.asset.get_by_guid(domain.guid, asset_type=DataDomain, ignore_relationships=False) + test_domain = client.asset.get_by_guid( + domain.guid, asset_type=DataDomain, ignore_relationships=False + ) assert test_domain assert test_domain.guid == domain.guid assert test_domain.qualified_name == domain.qualified_name @@ -193,7 +195,9 @@ def test_update_sub_domain(client: AtlanClient, sub_domain: DataDomain): @pytest.mark.order(after="test_update_sub_domain") def test_retrieve_sub_domain(client: AtlanClient, sub_domain: DataDomain): - test_sub_domain = client.asset.get_by_guid(sub_domain.guid, asset_type=DataDomain, ignore_relationships=False) + test_sub_domain = client.asset.get_by_guid( + sub_domain.guid, asset_type=DataDomain, ignore_relationships=False + ) assert test_sub_domain assert test_sub_domain.guid == sub_domain.guid assert test_sub_domain.qualified_name == sub_domain.qualified_name @@ -339,12 +343,16 @@ def test_contract( client: AtlanClient, table: Table, product: DataProduct, contract: DataContract ): assert product and product.guid - product = client.asset.get_by_guid(guid=product.guid, asset_type=DataProduct, ignore_relationships=False) + product = client.asset.get_by_guid( + guid=product.guid, asset_type=DataProduct, ignore_relationships=False + ) assert product and product.output_ports and len(product.output_ports) table_asset = product.output_ports[0] assert table and table.guid assert table.guid == table_asset.guid - table = client.asset.get_by_guid(guid=table_asset.guid, asset_type=Table, ignore_relationships=False) + table = client.asset.get_by_guid( + guid=table_asset.guid, asset_type=Table, ignore_relationships=False + ) assert table.has_contract assert table.data_contract_latest table_data_contract = table.data_contract_latest @@ -360,7 +368,9 @@ def test_update_contract( client: AtlanClient, table: Table, updated_contract: DataContract ): assert table and table.guid - table = client.asset.get_by_guid(guid=table.guid, asset_type=Table, ignore_relationships=False) + table = client.asset.get_by_guid( + guid=table.guid, asset_type=Table, ignore_relationships=False + ) assert table.has_contract assert table.data_contract_latest table_data_contract = table.data_contract_latest @@ -436,7 +446,9 @@ def test_update_product( @pytest.mark.order(after="test_update_product") def test_retrieve_product(client: AtlanClient, product: DataProduct): - test_product = client.asset.get_by_guid(product.guid, asset_type=DataProduct, ignore_relationships=False) + test_product = client.asset.get_by_guid( + product.guid, asset_type=DataProduct, ignore_relationships=False + ) assert test_product assert test_product.guid == product.guid assert test_product.qualified_name == product.qualified_name diff --git a/tests/integration/data_studio_asset_test.py b/tests/integration/data_studio_asset_test.py index d6ad073f..56b3a51e 100644 --- a/tests/integration/data_studio_asset_test.py +++ b/tests/integration/data_studio_asset_test.py @@ -192,7 +192,9 @@ def test_retrieve_data_studio_asset_data_source( data_studio_asset_data_source: DataStudioAsset, ): b = client.asset.get_by_guid( - data_studio_asset_data_source.guid, asset_type=DataStudioAsset, ignore_relationships=False + data_studio_asset_data_source.guid, + asset_type=DataStudioAsset, + ignore_relationships=False, ) assert b assert not b.is_incomplete @@ -261,7 +263,9 @@ def test_read_deleted_data_studio_asset_data_source( data_studio_asset_data_source: DataStudioAsset, ): deleted = client.asset.get_by_guid( - data_studio_asset_data_source.guid, asset_type=DataStudioAsset, ignore_relationships=False + data_studio_asset_data_source.guid, + asset_type=DataStudioAsset, + ignore_relationships=False, ) assert deleted assert deleted.guid == data_studio_asset_data_source.guid @@ -283,7 +287,8 @@ def test_restore_data_studio_asset_data_source( assert data_studio_asset_data_source.qualified_name restored = client.asset.get_by_qualified_name( asset_type=DataStudioAsset, - qualified_name=data_studio_asset_data_source.qualified_name, ignore_relationships=False + qualified_name=data_studio_asset_data_source.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == data_studio_asset_data_source.guid diff --git a/tests/integration/gcs_asset_test.py b/tests/integration/gcs_asset_test.py index 0554d3a0..122664f0 100644 --- a/tests/integration/gcs_asset_test.py +++ b/tests/integration/gcs_asset_test.py @@ -164,7 +164,9 @@ def test_retrieve_gcs_object( gcs_bucket: GCSBucket, gcs_object: GCSObject, ): - b = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject, ignore_relationships=False) + b = client.asset.get_by_guid( + gcs_object.guid, asset_type=GCSObject, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == gcs_object.guid @@ -235,7 +237,9 @@ def test_read_deleted_gcs_object( gcs_bucket: GCSBucket, gcs_object: GCSObject, ): - deleted = client.asset.get_by_guid(gcs_object.guid, asset_type=GCSObject, ignore_relationships=False) + deleted = client.asset.get_by_guid( + gcs_object.guid, asset_type=GCSObject, ignore_relationships=False + ) assert deleted assert deleted.guid == gcs_object.guid assert deleted.qualified_name == gcs_object.qualified_name @@ -255,7 +259,9 @@ def test_restore_object( ) assert gcs_object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=GCSObject, qualified_name=gcs_object.qualified_name, ignore_relationships=False + asset_type=GCSObject, + qualified_name=gcs_object.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == gcs_object.guid diff --git a/tests/integration/glossary_test.py b/tests/integration/glossary_test.py index 47af760c..5a7932f9 100644 --- a/tests/integration/glossary_test.py +++ b/tests/integration/glossary_test.py @@ -270,7 +270,9 @@ def test_category( assert category.guid assert category.name == MODULE_NAME assert category.qualified_name - c = client.asset.get_by_guid(category.guid, AtlasGlossaryCategory, ignore_relationships=False) + c = client.asset.get_by_guid( + category.guid, AtlasGlossaryCategory, ignore_relationships=False + ) assert c assert c.guid == category.guid assert c.anchor @@ -311,7 +313,9 @@ def test_term1( assert term1.name == TERM_NAME1 assert term1.qualified_name assert term1.qualified_name != TERM_NAME1 - t = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + t = client.asset.get_by_guid( + term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert t assert t.guid == term1.guid assert t.attributes.anchor @@ -336,7 +340,9 @@ def test_term2( assert term2.name == TERM_NAME2 assert term2.qualified_name assert term2.qualified_name != TERM_NAME2 - t = client.asset.get_by_guid(term2.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + t = client.asset.get_by_guid( + term2.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert t assert t.guid == term2.guid assert t.attributes.anchor @@ -361,7 +367,9 @@ def test_term3( assert term3.name == TERM_NAME3 assert term3.qualified_name assert term3.qualified_name != TERM_NAME3 - t = client.asset.get_by_guid(term3.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + t = client.asset.get_by_guid( + term3.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert t assert t.guid == term3.guid assert t.attributes.anchor @@ -386,7 +394,9 @@ def test_term4( assert term4.name == TERM_NAME4 assert term4.qualified_name assert term4.qualified_name != TERM_NAME4 - t = client.asset.get_by_guid(term4.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + t = client.asset.get_by_guid( + term4.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert t assert t.guid == term4.guid assert t.attributes.anchor @@ -401,7 +411,9 @@ def test_read_glossary( term3: AtlasGlossaryTerm, term4: AtlasGlossaryTerm, ): - g = client.asset.get_by_guid(glossary.guid, asset_type=AtlasGlossary, ignore_relationships=False) + g = client.asset.get_by_guid( + glossary.guid, asset_type=AtlasGlossary, ignore_relationships=False + ) assert g assert isinstance(g, AtlasGlossary) assert g.guid == glossary.guid @@ -540,7 +552,9 @@ def test_term_trim_to_required( client: AtlanClient, term1: AtlasGlossaryTerm, ): - term1 = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + term1 = client.asset.get_by_guid( + guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) term1 = term1.trim_to_required() response = client.asset.save(term1) assert response.mutated_entities is None @@ -801,7 +815,9 @@ def test_create_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + result = client.asset.get_by_guid( + guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert result assert result.see_also assert len(result.see_also) == 2 @@ -836,7 +852,9 @@ def test_remove_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + result = client.asset.get_by_guid( + guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert result assert result.see_also active_relationships = [] @@ -871,7 +889,9 @@ def test_append_relationship( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + result = client.asset.get_by_guid( + guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert result assert result.see_also active_relationships = [] @@ -907,7 +927,9 @@ def test_append_relationship_again( response = client.asset.save(term) assert response - result = client.asset.get_by_guid(guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + result = client.asset.get_by_guid( + guid=term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert result assert result.see_also active_relationships = [] diff --git a/tests/integration/kafka_asset_test.py b/tests/integration/kafka_asset_test.py index b4288bf4..f49f7f6b 100644 --- a/tests/integration/kafka_asset_test.py +++ b/tests/integration/kafka_asset_test.py @@ -143,7 +143,9 @@ def test_update_kafka_assets( def _retrieve_kafka_assets(client, asset, asset_type): - retrieved = client.asset.get_by_guid(asset.guid, asset_type=asset_type, ignore_relationships=False) + retrieved = client.asset.get_by_guid( + asset.guid, asset_type=asset_type, ignore_relationships=False + ) assert retrieved assert not retrieved.is_incomplete assert retrieved.guid == asset.guid @@ -208,7 +210,9 @@ def test_restore_kafka_consumer_group( ) assert consumer_group.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=KafkaConsumerGroup, qualified_name=consumer_group.qualified_name, ignore_relationships=False + asset_type=KafkaConsumerGroup, + qualified_name=consumer_group.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == consumer_group.guid diff --git a/tests/integration/lineage_test.py b/tests/integration/lineage_test.py index d74a2bae..91ec8628 100644 --- a/tests/integration/lineage_test.py +++ b/tests/integration/lineage_test.py @@ -701,13 +701,17 @@ def test_restore_lineage( ) to_restore.status = EntityStatus.ACTIVE client.asset.save(to_restore) - restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process, ignore_relationships=False) + restored = client.asset.get_by_guid( + lineage_start.guid, asset_type=Process, ignore_relationships=False + ) assert restored count = 0 # TODO: replace with exponential back-off and jitter while restored.status == EntityStatus.DELETED: time.sleep(2) - restored = client.asset.get_by_guid(lineage_start.guid, asset_type=Process, ignore_relationships=False) + restored = client.asset.get_by_guid( + lineage_start.guid, asset_type=Process, ignore_relationships=False + ) count += 1 assert restored.guid == lineage_start.guid assert restored.qualified_name == lineage_start.qualified_name diff --git a/tests/integration/persona_test.py b/tests/integration/persona_test.py index aa40e354..9e51a8b9 100644 --- a/tests/integration/persona_test.py +++ b/tests/integration/persona_test.py @@ -170,7 +170,9 @@ def test_retrieve_persona( ): assert persona.qualified_name one = client.asset.get_by_qualified_name( - qualified_name=persona.qualified_name, asset_type=Persona, ignore_relationships=False + qualified_name=persona.qualified_name, + asset_type=Persona, + ignore_relationships=False, ) assert one assert one.guid == persona.guid @@ -187,7 +189,9 @@ def test_retrieve_persona( for policy in policies: # Need to retrieve the full policy if we want to see any info about it # (what comes back on the Persona itself are just policy references) - full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False) + full = client.asset.get_by_guid( + guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False + ) assert full sub_cat = full.policy_sub_category assert sub_cat diff --git a/tests/integration/preset_asset_test.py b/tests/integration/preset_asset_test.py index 35e0a82e..24284691 100644 --- a/tests/integration/preset_asset_test.py +++ b/tests/integration/preset_asset_test.py @@ -335,7 +335,9 @@ def test_retrieve_preset_dashboard( client: AtlanClient, preset_dashboard: PresetDashboard, ): - b = client.asset.get_by_guid(preset_dashboard.guid, asset_type=PresetDashboard, ignore_relationships=False) + b = client.asset.get_by_guid( + preset_dashboard.guid, asset_type=PresetDashboard, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == preset_dashboard.guid @@ -404,7 +406,9 @@ def test_restore_dashboard( ) assert preset_dashboard.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=PresetDashboard, qualified_name=preset_dashboard.qualified_name, ignore_relationships=False + asset_type=PresetDashboard, + qualified_name=preset_dashboard.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == preset_dashboard.guid diff --git a/tests/integration/purpose_test.py b/tests/integration/purpose_test.py index 00ee6a78..b12155ba 100644 --- a/tests/integration/purpose_test.py +++ b/tests/integration/purpose_test.py @@ -133,7 +133,9 @@ def test_purpose(client: AtlanClient, purpose: Purpose, atlan_tag_name: AtlanTag assert purpose.name == MODULE_NAME assert purpose.display_name == MODULE_NAME assert purpose.qualified_name != MODULE_NAME - purpose = client.asset.get_by_guid(guid=purpose.guid, asset_type=Purpose, ignore_relationships=False) + purpose = client.asset.get_by_guid( + guid=purpose.guid, asset_type=Purpose, ignore_relationships=False + ) assert purpose.purpose_atlan_tags assert [atlan_tag_name] == purpose.purpose_atlan_tags @@ -226,7 +228,9 @@ def test_retrieve_purpose( ): assert purpose.qualified_name one = client.asset.get_by_qualified_name( - qualified_name=purpose.qualified_name, asset_type=Purpose, ignore_relationships=False + qualified_name=purpose.qualified_name, + asset_type=Purpose, + ignore_relationships=False, ) assert one assert one.guid == purpose.guid @@ -244,7 +248,9 @@ def test_retrieve_purpose( for policy in policies: # Need to retrieve the full policy if we want to see any info about it # (what comes back on the Persona itself are just policy references) - full = client.asset.get_by_guid(guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False) + full = client.asset.get_by_guid( + guid=policy.guid, asset_type=AuthPolicy, ignore_relationships=False + ) assert full sub_cat = full.policy_sub_category assert sub_cat diff --git a/tests/integration/s3_asset_test.py b/tests/integration/s3_asset_test.py index a548356b..5b22de87 100644 --- a/tests/integration/s3_asset_test.py +++ b/tests/integration/s3_asset_test.py @@ -181,7 +181,9 @@ def _assert_update_bucket(client, bucket, with_name=False): def _assert_retrieve_bucket(client, bucket, s3object, with_name=False): - b = client.asset.get_by_guid(bucket.guid, asset_type=S3Bucket, ignore_relationships=False) + b = client.asset.get_by_guid( + bucket.guid, asset_type=S3Bucket, ignore_relationships=False + ) assert b assert not b.is_incomplete assert b.guid == bucket.guid @@ -244,7 +246,9 @@ def _assert_delete_object(client, s3object): def _assert_read_delete_object(client, s3object): - deleted = client.asset.get_by_guid(s3object.guid, asset_type=S3Object, ignore_relationships=False) + deleted = client.asset.get_by_guid( + s3object.guid, asset_type=S3Object, ignore_relationships=False + ) assert deleted assert deleted.guid == s3object.guid assert deleted.qualified_name == s3object.qualified_name @@ -258,7 +262,9 @@ def _assert_restore_object(client, s3object): ) assert s3object.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=S3Object, qualified_name=s3object.qualified_name, ignore_relationships=False + asset_type=S3Object, + qualified_name=s3object.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == s3object.guid diff --git a/tests/integration/superset_asset_test.py b/tests/integration/superset_asset_test.py index 049e72dd..6113186b 100644 --- a/tests/integration/superset_asset_test.py +++ b/tests/integration/superset_asset_test.py @@ -274,7 +274,11 @@ def test_retrieve_superset_dashboard( client: AtlanClient, superset_dashboard: SupersetDashboard, ): - b = client.asset.get_by_guid(superset_dashboard.guid, asset_type=SupersetDashboard, ignore_relationships=False) + b = client.asset.get_by_guid( + superset_dashboard.guid, + asset_type=SupersetDashboard, + ignore_relationships=False, + ) assert b assert not b.is_incomplete assert b.guid == superset_dashboard.guid @@ -343,7 +347,9 @@ def test_restore_dashboard( ) assert superset_dashboard.qualified_name restored = client.asset.get_by_qualified_name( - asset_type=SupersetDashboard, qualified_name=superset_dashboard.qualified_name, ignore_relationships=False + asset_type=SupersetDashboard, + qualified_name=superset_dashboard.qualified_name, + ignore_relationships=False, ) assert restored assert restored.guid == superset_dashboard.guid diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index 7837e3c0..a0033164 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -237,7 +237,9 @@ def test_append_terms_with_guid( guid=database.guid, asset_type=Database, terms=[term1] ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -253,7 +255,9 @@ def test_append_terms_with_qualified_name( qualified_name=database.qualified_name, asset_type=Database, terms=[term1] ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -271,7 +275,9 @@ def test_append_terms_using_ref_by_guid_for_term( terms=[AtlasGlossaryTerm.ref_by_guid(guid=term1.guid)], ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 1 assert database.assigned_terms[0].guid == term1.guid @@ -297,7 +303,9 @@ def test_replace_a_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 2 deleted_terms = [ @@ -331,7 +339,9 @@ def test_replace_all_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships=False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 1 deleted_terms = [ @@ -366,7 +376,9 @@ def test_remove_term( ) ) - database = client.asset.get_by_guid(guid=database.guid, asset_type=Database, ignore_relationships= False) + database = client.asset.get_by_guid( + guid=database.guid, asset_type=Database, ignore_relationships=False + ) assert database.assigned_terms assert len(database.assigned_terms) == 2 deleted_terms = [ @@ -391,7 +403,9 @@ def test_find_connections_by_name(client: AtlanClient): def test_get_asset_by_guid_good_guid(client: AtlanClient, glossary: AtlasGlossary): - glossary = client.asset.get_by_guid(glossary.guid, AtlasGlossary, ignore_relationships=False) + glossary = client.asset.get_by_guid( + glossary.guid, AtlasGlossary, ignore_relationships=False + ) assert isinstance(glossary, AtlasGlossary) @@ -463,7 +477,9 @@ def test_add_classification(client: AtlanClient, term1: AtlasGlossaryTerm): client.asset.add_atlan_tags( AtlasGlossaryTerm, term1.qualified_name, [CLASSIFICATION_NAME] ) - glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + glossary_term = client.asset.get_by_guid( + term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert glossary_term.atlan_tags assert len(glossary_term.atlan_tags) == 1 classification = glossary_term.atlan_tags[0] @@ -504,7 +520,9 @@ def test_remove_classification(client: AtlanClient, term1: AtlasGlossaryTerm): client.asset.remove_atlan_tag( AtlasGlossaryTerm, term1.qualified_name, CLASSIFICATION_NAME ) - glossary_term = client.asset.get_by_guid(term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False) + glossary_term = client.asset.get_by_guid( + term1.guid, asset_type=AtlasGlossaryTerm, ignore_relationships=False + ) assert not glossary_term.atlan_tags diff --git a/tests/integration/test_index_search.py b/tests/integration/test_index_search.py index cc3a57af..b49f1cf0 100644 --- a/tests/integration/test_index_search.py +++ b/tests/integration/test_index_search.py @@ -184,7 +184,9 @@ def test_search_source_synced_assets(client: AtlanClient): def test_source_tag_assign_with_value(client: AtlanClient, table: Table): # Make sure no tags are assigned initially assert table.guid - table = client.asset.get_by_guid(guid=table.guid, asset_type=Table, ignore_relationships=False) + table = client.asset.get_by_guid( + guid=table.guid, asset_type=Table, ignore_relationships=False + ) assert not table.atlan_tags assert table.name and table.qualified_name diff --git a/tests/integration/test_sql_assets.py b/tests/integration/test_sql_assets.py index d7e1039a..1d2a90c7 100644 --- a/tests/integration/test_sql_assets.py +++ b/tests/integration/test_sql_assets.py @@ -196,10 +196,14 @@ def test_create( response = upsert(schema) assert (schemas := response.assets_created(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(schemas[0].guid, Schema, ignore_relationships=False) + schema = client.asset.get_by_guid( + schemas[0].guid, Schema, ignore_relationships=False + ) assert (databases := response.assets_updated(asset_type=Database)) assert len(databases) == 1 - database = client.asset.get_by_guid(databases[0].guid, Database, ignore_relationships=False) + database = client.asset.get_by_guid( + databases[0].guid, Database, ignore_relationships=False + ) assert database.attributes.schemas schemas = database.attributes.schemas assert len(schemas) == 1 @@ -227,10 +231,14 @@ def test_overload_creator( response = upsert(schema) assert (schemas := response.assets_created(asset_type=Schema)) assert len(schemas) == 1 - overload_schema = client.asset.get_by_guid(schemas[0].guid, Schema, ignore_relationships=False) + overload_schema = client.asset.get_by_guid( + schemas[0].guid, Schema, ignore_relationships=False + ) assert (databases := response.assets_updated(asset_type=Database)) assert len(databases) == 1 - database = client.asset.get_by_guid(databases[0].guid, Database, ignore_relationships=False) + database = client.asset.get_by_guid( + databases[0].guid, Database, ignore_relationships=False + ) assert database.attributes.schemas schemas = database.attributes.schemas assert len(schemas) == 2 @@ -299,10 +307,14 @@ def test_create( response = upsert(table) assert (tables := response.assets_created(asset_type=Table)) assert len(tables) == 1 - table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table, ignore_relationships=False) + table = client.asset.get_by_guid( + guid=tables[0].guid, asset_type=Table, ignore_relationships=False + ) assert (schemas := response.assets_updated(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False) + schema = client.asset.get_by_guid( + guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False + ) assert schema.attributes.tables tables = schema.attributes.tables assert len(tables) == 1 @@ -335,10 +347,14 @@ def test_overload_creator( response = upsert(table) assert (tables := response.assets_created(asset_type=Table)) assert len(tables) == 1 - overload_table = client.asset.get_by_guid(guid=tables[0].guid, asset_type=Table, ignore_relationships=False) + overload_table = client.asset.get_by_guid( + guid=tables[0].guid, asset_type=Table, ignore_relationships=False + ) assert (schemas := response.assets_updated(asset_type=Schema)) assert len(schemas) == 1 - schema = client.asset.get_by_guid(guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False) + schema = client.asset.get_by_guid( + guid=schemas[0].guid, asset_type=Schema, ignore_relationships=False + ) assert schema.attributes.tables tables = schema.attributes.tables assert len(tables) == 2 @@ -395,7 +411,9 @@ def test_source_read_recent_user_record_list_readable( popularity_insight: PopularityInsights, ): assert TestTable.table - asset = client.asset.get_by_guid(guid=TestTable.table.guid, asset_type=Table, ignore_relationships=False) + asset = client.asset.get_by_guid( + guid=TestTable.table.guid, asset_type=Table, ignore_relationships=False + ) assert asset.source_read_recent_user_record_list asset_popularity = asset.source_read_recent_user_record_list[0] self.verify_popularity(asset_popularity, popularity_insight) @@ -551,8 +569,12 @@ def test_create( response = client.asset.save(column) assert (columns := response.assets_created(asset_type=Column)) assert len(columns) == 1 - column = client.asset.get_by_guid(asset_type=Column, guid=columns[0].guid, ignore_relationships=False) - table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False) + column = client.asset.get_by_guid( + asset_type=Column, guid=columns[0].guid, ignore_relationships=False + ) + table = client.asset.get_by_guid( + asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False + ) assert table.attributes.columns columns = table.attributes.columns assert len(columns) == 1 @@ -626,7 +648,9 @@ def test_overload_creator( overload_column = client.asset.get_by_guid( asset_type=Column, guid=columns[0].guid, ignore_relationships=False ) - table = client.asset.get_by_guid(asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False) + table = client.asset.get_by_guid( + asset_type=Table, guid=TestTable.table.guid, ignore_relationships=False + ) assert table.attributes.columns columns = table.attributes.columns @@ -692,7 +716,9 @@ def test_create( assert len(reaadmes) == 1 assert (columns := response.assets_updated(asset_type=Column)) assert len(columns) == 1 - readme = client.asset.get_by_guid(guid=reaadmes[0].guid, asset_type=Readme, ignore_relationships=False) + readme = client.asset.get_by_guid( + guid=reaadmes[0].guid, asset_type=Readme, ignore_relationships=False + ) assert readme.description == self.CONTENT TestReadme.readme = readme diff --git a/tests/integration/utils.py b/tests/integration/utils.py index f30c7e08..b29a30f7 100644 --- a/tests/integration/utils.py +++ b/tests/integration/utils.py @@ -33,7 +33,9 @@ def retrieve_and_check_assets( leftovers = [] for one in to_check: try: - candidate = client.asset.get_by_guid(one.guid, asset_type=type(one), ignore_relationships=False) + candidate = client.asset.get_by_guid( + one.guid, asset_type=type(one), ignore_relationships=False + ) if candidate and candidate.status == EntityStatus.ACTIVE: leftovers.append(candidate) except NotFoundError: diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 62c7f319..bd1d8e8e 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1555,7 +1555,9 @@ def test_asset_get_by_guid_without_asset_type(mock_api_caller, get_by_guid_json) client = AssetClient(mock_api_caller) mock_api_caller._call_api.side_effect = [get_by_guid_json] - response = client.get_by_guid(guid="test-table-guid-123", ignore_relationships=False) + response = client.get_by_guid( + guid="test-table-guid-123", ignore_relationships=False + ) assert response assert isinstance(response, Table) From 2d69fa80cccc2b2f03207f96a369e09bbc05c787 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 17:40:56 +0530 Subject: [PATCH 06/66] Added unit tests. --- tests/unit/test_client.py | 95 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index bd1d8e8e..676ef0ad 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -39,6 +39,7 @@ DataDomain, DataProduct, Table, + View, ) from pyatlan.model.core import Announcement, BulkRequest from pyatlan.model.enums import ( @@ -2364,3 +2365,97 @@ def test_get_all_sorting(group_client, mock_api_caller): query_params = mock_api_caller._call_api.call_args.kwargs["query_params"] assert query_params["sort"] == "alias" mock_api_caller.reset_mock() + + +def test_get_by_guid_asset_not_found_fluent_search(): + guid = "123" + asset_type = Table + + with patch("pyatlan.model.fluent_search.FluentSearch.execute") as mock_execute: + mock_execute.return_value.current_page.return_value = [] + + client = AssetClient(client=ApiCaller) + with pytest.raises( + ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid).__class__ + ): + client.get_by_guid( + guid=guid, + asset_type=asset_type, + attributes=["name"], + relationships_attributes=["owner"], + ) + + mock_execute.assert_called_once() + + +def test_get_by_guid_type_mismatch_fluent_search(): + guid = "123" + expected_asset_type = Table + returned_asset_type = View + + with patch("pyatlan.model.fluent_search.FluentSearch.execute") as mock_execute: + mock_execute.return_value.current_page.return_value = [returned_asset_type()] + + client = AssetClient(client=ApiCaller) + + with pytest.raises( + ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, expected_asset_type.__name__ + ).__class__ + ): + client.get_by_guid( + guid=guid, + asset_type=expected_asset_type, + attributes=["name"], + relationships_attributes=["owner"], + ) + + mock_execute.assert_called_once() + + +def test_get_by_qualified_name_type_mismatch(): + qualified_name = "example_qualified_name" + expected_asset_type = Table + returned_asset_type = View + + with patch("pyatlan.model.fluent_search.FluentSearch.execute") as mock_execute: + mock_execute.return_value.current_page.return_value = [returned_asset_type()] + + client = AssetClient(client=ApiCaller) + + with pytest.raises( + ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + expected_asset_type.__name__, qualified_name + ).__class__ + ): + client.get_by_qualified_name( + qualified_name=qualified_name, + asset_type=expected_asset_type, + attributes=["name"], + relationships_attributes=["owner"], + ) + mock_execute.assert_called_once() + + +def test_get_by_qualified_name_asset_not_found(): + qualified_name = "example_qualified_name" + asset_type = Table + + with patch("pyatlan.model.fluent_search.FluentSearch.execute") as mock_execute: + mock_execute.return_value.current_page.return_value = [] + + client = AssetClient(client=ApiCaller) + + with pytest.raises( + ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( + qualified_name, asset_type.__name__ + ).__class__ + ): + client.get_by_qualified_name( + qualified_name=qualified_name, + asset_type=asset_type, + attributes=["name"], + relationships_attributes=["owner"], + ) + + mock_execute.assert_called_once() From aa437d79649fed3b22559dec274f3fe92c09266c Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 21:43:47 +0530 Subject: [PATCH 07/66] Added Integration Tests --- testing.py | 26 -------------------------- tests/integration/test_client.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/testing.py b/testing.py index db354b3a..e69de29b 100644 --- a/testing.py +++ b/testing.py @@ -1,26 +0,0 @@ -from pyatlan.client.atlan import AtlanClient - -# GUID="3e939271-abbd-42bf-9188-9cff9ee36387" -# request = FluentSearch().select().where(Asset.GUID.eq(GUID)) -# .include_on_results(["qualified_name","name"]).execute(client) - -# candidate = (response.current_page() and response.current_page()[0]) or None -# print(candidate) - -client = AtlanClient() - -response = client.asset.get_by_guid(guid="3e939271-abbd-42bf-9188-9cff9ee36387") -print(response) -print("next") -# client = AtlanClient() - -# GUID = "3e939271-abbd-42bf-9188-9cff9ee36387" -# request = ( -# FluentSearch() -# .select() -# .where(Asset.GUID.eq(GUID)) -# .include_on_results(["qualified_name", "name"]) # Ensure all elements are strings -# .execute(client) -# ) - -# print(request) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index a0033164..c704f175 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -7,6 +7,7 @@ from pydantic.v1 import StrictStr from pyatlan.client.atlan import DEFAULT_RETRY, AtlanClient +from pyatlan.client.asset import AssetClient from pyatlan.client.audit import LOGGER as AUDIT_LOGGER from pyatlan.client.search_log import LOGGER as SEARCH_LOG_LOGGER from pyatlan.client.search_log import ( @@ -433,6 +434,35 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not ): client.asset.get_by_guid(guid, Table, ignore_relationships=False) +def test_get_by_guid_ignore_relationships(client:AtlanClient, glossary: AtlasGlossary): + result = client.asset.get_by_guid( + guid=glossary.guid, ignore_relationships=True + ) + print(result.relationship_attributes) + assert result.guid == glossary.guid + +def test_get_by_guid_with_attributes(client:AtlanClient, glossary: AtlasGlossary): + attributes = ["name", "qualified_name"] + + result = client.asset.get_by_guid( + guid=glossary.guid, + attributes=attributes + ) + assert result.guid == glossary.guid + assert hasattr(result, "attributes") + assert result.attributes.qualified_name is not None + assert result.attributes.name is not None + +def test_get_by_QN_with_attributes(client: AtlanClient, glossary: AtlasGlossary): + qualified_name = glossary.qualified_name or "" + result = client.asset.get_by_qualified_name( + qualified_name=qualified_name, asset_type=AtlasGlossary, ignore_relationships=True, attributes=["name", "qualified_name"] + ) + assert result.qualified_name == glossary.qualified_name + assert hasattr(result, "attributes") + assert result.attributes.qualified_name is not None + assert result.attributes.name is not None + def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error( client: AtlanClient, @@ -1264,4 +1294,4 @@ def test_client_401_token_refresh( # Confirm the API key has been updated and results are returned assert client.api_key != expired_api_token - assert results and results.count >= 1 + assert results and results.count >= 1 \ No newline at end of file From 2332f34452e98157941cc091245d5a136d474074 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 21:45:14 +0530 Subject: [PATCH 08/66] Added Integration Tests --- tests/integration/test_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index c704f175..85d615df 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -438,7 +438,6 @@ def test_get_by_guid_ignore_relationships(client:AtlanClient, glossary: AtlasGlo result = client.asset.get_by_guid( guid=glossary.guid, ignore_relationships=True ) - print(result.relationship_attributes) assert result.guid == glossary.guid def test_get_by_guid_with_attributes(client:AtlanClient, glossary: AtlasGlossary): From 0747f90e63ffc8715985eaa41d940227642bc421 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Mon, 30 Dec 2024 22:33:55 +0530 Subject: [PATCH 09/66] Corrected Integration tests and QA Checks --- tests/integration/test_client.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index 85d615df..85feac6e 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -7,7 +7,6 @@ from pydantic.v1 import StrictStr from pyatlan.client.atlan import DEFAULT_RETRY, AtlanClient -from pyatlan.client.asset import AssetClient from pyatlan.client.audit import LOGGER as AUDIT_LOGGER from pyatlan.client.search_log import LOGGER as SEARCH_LOG_LOGGER from pyatlan.client.search_log import ( @@ -434,33 +433,32 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not ): client.asset.get_by_guid(guid, Table, ignore_relationships=False) -def test_get_by_guid_ignore_relationships(client:AtlanClient, glossary: AtlasGlossary): - result = client.asset.get_by_guid( - guid=glossary.guid, ignore_relationships=True - ) - assert result.guid == glossary.guid -def test_get_by_guid_with_attributes(client:AtlanClient, glossary: AtlasGlossary): +def test_get_by_guid_with_attributes(client: AtlanClient, glossary: AtlasGlossary): attributes = ["name", "qualified_name"] result = client.asset.get_by_guid( - guid=glossary.guid, - attributes=attributes + guid=glossary.guid, asset_type=AtlasGlossary, attributes=attributes ) assert result.guid == glossary.guid assert hasattr(result, "attributes") assert result.attributes.qualified_name is not None assert result.attributes.name is not None + assert result.attributes.admin_groups is None + def test_get_by_QN_with_attributes(client: AtlanClient, glossary: AtlasGlossary): qualified_name = glossary.qualified_name or "" result = client.asset.get_by_qualified_name( - qualified_name=qualified_name, asset_type=AtlasGlossary, ignore_relationships=True, attributes=["name", "qualified_name"] + qualified_name=qualified_name, + asset_type=AtlasGlossary, + attributes=["name", "qualified_name"], ) assert result.qualified_name == glossary.qualified_name assert hasattr(result, "attributes") assert result.attributes.qualified_name is not None assert result.attributes.name is not None + assert result.attributes.admin_groups is None def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error( @@ -1293,4 +1291,4 @@ def test_client_401_token_refresh( # Confirm the API key has been updated and results are returned assert client.api_key != expired_api_token - assert results and results.count >= 1 \ No newline at end of file + assert results and results.count >= 1 From 150c42d26abac892d9ef1f0ece7e9fe74a64b6c8 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Mon, 30 Dec 2024 22:35:00 +0530 Subject: [PATCH 10/66] Delete testing.py Added by mistake --- testing.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 testing.py diff --git a/testing.py b/testing.py deleted file mode 100644 index e69de29b..00000000 From 3271571e20d776252b6c34ac4ac9b3e562c9b3f8 Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 13:46:26 +0530 Subject: [PATCH 11/66] anaplan initial generated files --- docs/asset/anaplan.rst | 10 ++ docs/asset/anaplanapp.rst | 10 ++ docs/asset/anaplandimension.rst | 10 ++ docs/asset/anaplanlineitem.rst | 10 ++ docs/asset/anaplanlist.rst | 10 ++ docs/asset/anaplanmodel.rst | 10 ++ docs/asset/anaplanmodule.rst | 10 ++ docs/asset/anaplanpage.rst | 10 ++ docs/asset/anaplanview.rst | 10 ++ docs/asset/anaplanworkspace.rst | 10 ++ docs/assets.rst | 10 ++ pyatlan/model/assets/__init__.py | 10 ++ pyatlan/model/assets/__init__.pyi | 20 +++ pyatlan/model/assets/anaplan.py | 200 ++++++++++++++++++++++ pyatlan/model/assets/anaplan_app.py | 68 ++++++++ pyatlan/model/assets/anaplan_dimension.py | 142 +++++++++++++++ pyatlan/model/assets/anaplan_line_item.py | 129 ++++++++++++++ pyatlan/model/assets/anaplan_list.py | 108 ++++++++++++ pyatlan/model/assets/anaplan_model.py | 144 ++++++++++++++++ pyatlan/model/assets/anaplan_module.py | 106 ++++++++++++ pyatlan/model/assets/anaplan_page.py | 150 ++++++++++++++++ pyatlan/model/assets/anaplan_view.py | 143 ++++++++++++++++ pyatlan/model/assets/anaplan_workspace.py | 123 +++++++++++++ 23 files changed, 1453 insertions(+) create mode 100644 docs/asset/anaplan.rst create mode 100644 docs/asset/anaplanapp.rst create mode 100644 docs/asset/anaplandimension.rst create mode 100644 docs/asset/anaplanlineitem.rst create mode 100644 docs/asset/anaplanlist.rst create mode 100644 docs/asset/anaplanmodel.rst create mode 100644 docs/asset/anaplanmodule.rst create mode 100644 docs/asset/anaplanpage.rst create mode 100644 docs/asset/anaplanview.rst create mode 100644 docs/asset/anaplanworkspace.rst create mode 100644 pyatlan/model/assets/anaplan.py create mode 100644 pyatlan/model/assets/anaplan_app.py create mode 100644 pyatlan/model/assets/anaplan_dimension.py create mode 100644 pyatlan/model/assets/anaplan_line_item.py create mode 100644 pyatlan/model/assets/anaplan_list.py create mode 100644 pyatlan/model/assets/anaplan_model.py create mode 100644 pyatlan/model/assets/anaplan_module.py create mode 100644 pyatlan/model/assets/anaplan_page.py create mode 100644 pyatlan/model/assets/anaplan_view.py create mode 100644 pyatlan/model/assets/anaplan_workspace.py diff --git a/docs/asset/anaplan.rst b/docs/asset/anaplan.rst new file mode 100644 index 00000000..f7cf45c3 --- /dev/null +++ b/docs/asset/anaplan.rst @@ -0,0 +1,10 @@ +.. _anaplan: + +Anaplan +======= + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: Anaplan + :members: diff --git a/docs/asset/anaplanapp.rst b/docs/asset/anaplanapp.rst new file mode 100644 index 00000000..a0084814 --- /dev/null +++ b/docs/asset/anaplanapp.rst @@ -0,0 +1,10 @@ +.. _anaplanapp: + +AnaplanApp +========== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanApp + :members: diff --git a/docs/asset/anaplandimension.rst b/docs/asset/anaplandimension.rst new file mode 100644 index 00000000..c5880e00 --- /dev/null +++ b/docs/asset/anaplandimension.rst @@ -0,0 +1,10 @@ +.. _anaplandimension: + +AnaplanDimension +================ + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanDimension + :members: diff --git a/docs/asset/anaplanlineitem.rst b/docs/asset/anaplanlineitem.rst new file mode 100644 index 00000000..bb09b1c0 --- /dev/null +++ b/docs/asset/anaplanlineitem.rst @@ -0,0 +1,10 @@ +.. _anaplanlineitem: + +AnaplanLineItem +=============== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanLineItem + :members: diff --git a/docs/asset/anaplanlist.rst b/docs/asset/anaplanlist.rst new file mode 100644 index 00000000..07123844 --- /dev/null +++ b/docs/asset/anaplanlist.rst @@ -0,0 +1,10 @@ +.. _anaplanlist: + +AnaplanList +=========== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanList + :members: diff --git a/docs/asset/anaplanmodel.rst b/docs/asset/anaplanmodel.rst new file mode 100644 index 00000000..1dac2f34 --- /dev/null +++ b/docs/asset/anaplanmodel.rst @@ -0,0 +1,10 @@ +.. _anaplanmodel: + +AnaplanModel +============ + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanModel + :members: diff --git a/docs/asset/anaplanmodule.rst b/docs/asset/anaplanmodule.rst new file mode 100644 index 00000000..31db02d8 --- /dev/null +++ b/docs/asset/anaplanmodule.rst @@ -0,0 +1,10 @@ +.. _anaplanmodule: + +AnaplanModule +============= + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanModule + :members: diff --git a/docs/asset/anaplanpage.rst b/docs/asset/anaplanpage.rst new file mode 100644 index 00000000..f05f3929 --- /dev/null +++ b/docs/asset/anaplanpage.rst @@ -0,0 +1,10 @@ +.. _anaplanpage: + +AnaplanPage +=========== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanPage + :members: diff --git a/docs/asset/anaplanview.rst b/docs/asset/anaplanview.rst new file mode 100644 index 00000000..88ac683f --- /dev/null +++ b/docs/asset/anaplanview.rst @@ -0,0 +1,10 @@ +.. _anaplanview: + +AnaplanView +=========== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanView + :members: diff --git a/docs/asset/anaplanworkspace.rst b/docs/asset/anaplanworkspace.rst new file mode 100644 index 00000000..fec885f9 --- /dev/null +++ b/docs/asset/anaplanworkspace.rst @@ -0,0 +1,10 @@ +.. _anaplanworkspace: + +AnaplanWorkspace +================ + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AnaplanWorkspace + :members: diff --git a/docs/assets.rst b/docs/assets.rst index af8df9ea..6d610bc0 100644 --- a/docs/assets.rst +++ b/docs/assets.rst @@ -29,6 +29,16 @@ You can interact with all of the following different kinds of assets: asset/airflow asset/airflowdag asset/airflowtask + asset/anaplan + asset/anaplanapp + asset/anaplandimension + asset/anaplanlineitem + asset/anaplanlist + asset/anaplanmodel + asset/anaplanmodule + asset/anaplanpage + asset/anaplanview + asset/anaplanworkspace asset/anomalo asset/anomalocheck asset/app diff --git a/pyatlan/model/assets/__init__.py b/pyatlan/model/assets/__init__.py index 37c7bc24..3dc9df50 100644 --- a/pyatlan/model/assets/__init__.py +++ b/pyatlan/model/assets/__init__.py @@ -147,6 +147,7 @@ "preset": ["Preset"], "mode": ["Mode"], "sigma": ["Sigma"], + "anaplan": ["Anaplan"], "tableau": ["Tableau"], "looker": ["Looker"], "domo": ["Domo"], @@ -200,6 +201,15 @@ "sigma_data_element_field": ["SigmaDataElementField"], "sigma_page": ["SigmaPage"], "sigma_data_element": ["SigmaDataElement"], + "anaplan_page": ["AnaplanPage"], + "anaplan_list": ["AnaplanList"], + "anaplan_line_item": ["AnaplanLineItem"], + "anaplan_workspace": ["AnaplanWorkspace"], + "anaplan_module": ["AnaplanModule"], + "anaplan_model": ["AnaplanModel"], + "anaplan_app": ["AnaplanApp"], + "anaplan_dimension": ["AnaplanDimension"], + "anaplan_view": ["AnaplanView"], "tableau_workbook": ["TableauWorkbook"], "tableau_datasource_field": ["TableauDatasourceField"], "tableau_calculated_field": ["TableauCalculatedField"], diff --git a/pyatlan/model/assets/__init__.pyi b/pyatlan/model/assets/__init__.pyi index 09c701fe..f91d0ccd 100644 --- a/pyatlan/model/assets/__init__.pyi +++ b/pyatlan/model/assets/__init__.pyi @@ -144,6 +144,7 @@ __all__ = [ "Preset", "Mode", "Sigma", + "Anaplan", "Tableau", "Looker", "Domo", @@ -197,6 +198,15 @@ __all__ = [ "SigmaDataElementField", "SigmaPage", "SigmaDataElement", + "AnaplanPage", + "AnaplanList", + "AnaplanLineItem", + "AnaplanWorkspace", + "AnaplanModule", + "AnaplanModel", + "AnaplanApp", + "AnaplanDimension", + "AnaplanView", "TableauWorkbook", "TableauDatasourceField", "TableauCalculatedField", @@ -305,6 +315,16 @@ from .a_p_i_path import APIPath from .a_p_i_query import APIQuery from .a_p_i_spec import APISpec from .a_w_s import AWS +from .anaplan import Anaplan +from .anaplan_app import AnaplanApp +from .anaplan_dimension import AnaplanDimension +from .anaplan_line_item import AnaplanLineItem +from .anaplan_list import AnaplanList +from .anaplan_model import AnaplanModel +from .anaplan_module import AnaplanModule +from .anaplan_page import AnaplanPage +from .anaplan_view import AnaplanView +from .anaplan_workspace import AnaplanWorkspace from .auth_service import AuthService from .azure import Azure from .azure_event_hub import AzureEventHub diff --git a/pyatlan/model/assets/anaplan.py b/pyatlan/model/assets/anaplan.py new file mode 100644 index 00000000..c593ed72 --- /dev/null +++ b/pyatlan/model/assets/anaplan.py @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import KeywordField + +from .core.b_i import BI + + +class Anaplan(BI): + """Description""" + + type_name: str = Field(default="Anaplan", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "Anaplan": + raise ValueError("must be Anaplan") + return v + + def __setattr__(self, name, value): + if name in Anaplan._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_WORKSPACE_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanWorkspaceQualifiedName", "anaplanWorkspaceQualifiedName" + ) + """ + Unique name of the AnaplanWorkspace asset that contains this asset(AnaplanModel and everthing under it's hierarchy). + """ + ANAPLAN_WORKSPACE_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanWorkspaceName", "anaplanWorkspaceName" + ) + """ + Simple name of the AnaplanWorkspace asset that contains this asset(AnaplanModel and everthing under it's hierarchy). + """ + ANAPLAN_MODEL_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanModelQualifiedName", "anaplanModelQualifiedName" + ) + """ + Unique name of the AnaplanModel asset that contains this asset(AnaplanModule and everthing under it's hierarchy). + """ + ANAPLAN_MODEL_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanModelName", "anaplanModelName" + ) + """ + Simple name of the AnaplanModel asset that contains this asset(AnaplanModule and everthing under it's hierarchy). + """ + ANAPLAN_MODULE_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanModuleQualifiedName", "anaplanModuleQualifiedName" + ) + """ + Unique name of the AnaplanModule asset that contains this asset(AnaplanLineItem, AnaplanList, AnaplanView and everthing under their hierarchy). + """ # noqa: E501 + ANAPLAN_MODULE_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanModuleName", "anaplanModuleName" + ) + """ + Simple name of the AnaplanModule asset that contains this asset(AnaplanLineItem, AnaplanList, AnaplanView and everthing under their hierarchy). + """ # noqa: E501 + ANAPLAN_SOURCE_ID: ClassVar[KeywordField] = KeywordField( + "anaplanSourceId", "anaplanSourceId" + ) + """ + Id/Guid of the Anaplan asset in the source system. + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_workspace_qualified_name", + "anaplan_workspace_name", + "anaplan_model_qualified_name", + "anaplan_model_name", + "anaplan_module_qualified_name", + "anaplan_module_name", + "anaplan_source_id", + ] + + @property + def anaplan_workspace_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_workspace_qualified_name + ) + + @anaplan_workspace_qualified_name.setter + def anaplan_workspace_qualified_name( + self, anaplan_workspace_qualified_name: Optional[str] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_workspace_qualified_name = ( + anaplan_workspace_qualified_name + ) + + @property + def anaplan_workspace_name(self) -> Optional[str]: + return ( + None if self.attributes is None else self.attributes.anaplan_workspace_name + ) + + @anaplan_workspace_name.setter + def anaplan_workspace_name(self, anaplan_workspace_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_workspace_name = anaplan_workspace_name + + @property + def anaplan_model_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_model_qualified_name + ) + + @anaplan_model_qualified_name.setter + def anaplan_model_qualified_name(self, anaplan_model_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_model_qualified_name = anaplan_model_qualified_name + + @property + def anaplan_model_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.anaplan_model_name + + @anaplan_model_name.setter + def anaplan_model_name(self, anaplan_model_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_model_name = anaplan_model_name + + @property + def anaplan_module_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_module_qualified_name + ) + + @anaplan_module_qualified_name.setter + def anaplan_module_qualified_name( + self, anaplan_module_qualified_name: Optional[str] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_module_qualified_name = anaplan_module_qualified_name + + @property + def anaplan_module_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.anaplan_module_name + + @anaplan_module_name.setter + def anaplan_module_name(self, anaplan_module_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_module_name = anaplan_module_name + + @property + def anaplan_source_id(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.anaplan_source_id + + @anaplan_source_id.setter + def anaplan_source_id(self, anaplan_source_id: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_source_id = anaplan_source_id + + class Attributes(BI.Attributes): + anaplan_workspace_qualified_name: Optional[str] = Field( + default=None, description="" + ) + anaplan_workspace_name: Optional[str] = Field(default=None, description="") + anaplan_model_qualified_name: Optional[str] = Field( + default=None, description="" + ) + anaplan_model_name: Optional[str] = Field(default=None, description="") + anaplan_module_qualified_name: Optional[str] = Field( + default=None, description="" + ) + anaplan_module_name: Optional[str] = Field(default=None, description="") + anaplan_source_id: Optional[str] = Field(default=None, description="") + + attributes: Anaplan.Attributes = Field( + default_factory=lambda: Anaplan.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +Anaplan.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_app.py b/pyatlan/model/assets/anaplan_app.py new file mode 100644 index 00000000..98cd508b --- /dev/null +++ b/pyatlan/model/assets/anaplan_app.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .anaplan import Anaplan + + +class AnaplanApp(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanApp", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanApp": + raise ValueError("must be AnaplanApp") + return v + + def __setattr__(self, name, value): + if name in AnaplanApp._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_PAGES: ClassVar[RelationField] = RelationField("anaplanPages") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_pages", + ] + + @property + def anaplan_pages(self) -> Optional[List[AnaplanPage]]: + return None if self.attributes is None else self.attributes.anaplan_pages + + @anaplan_pages.setter + def anaplan_pages(self, anaplan_pages: Optional[List[AnaplanPage]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_pages = anaplan_pages + + class Attributes(Anaplan.Attributes): + anaplan_pages: Optional[List[AnaplanPage]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanApp.Attributes = Field( + default_factory=lambda: AnaplanApp.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_page import AnaplanPage # noqa + +AnaplanApp.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_dimension.py b/pyatlan/model/assets/anaplan_dimension.py new file mode 100644 index 00000000..aaf61daf --- /dev/null +++ b/pyatlan/model/assets/anaplan_dimension.py @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .anaplan import Anaplan + + +class AnaplanDimension(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanDimension", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanDimension": + raise ValueError("must be AnaplanDimension") + return v + + def __setattr__(self, name, value): + if name in AnaplanDimension._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_PAGE_VIEWS: ClassVar[RelationField] = RelationField("anaplanPageViews") + """ + TBC + """ + ANAPLAN_COLUMN_VIEWS: ClassVar[RelationField] = RelationField("anaplanColumnViews") + """ + TBC + """ + ANAPLAN_LINE_ITEMS: ClassVar[RelationField] = RelationField("anaplanLineItems") + """ + TBC + """ + ANAPLAN_MODEL: ClassVar[RelationField] = RelationField("anaplanModel") + """ + TBC + """ + ANAPLAN_ROW_VIEWS: ClassVar[RelationField] = RelationField("anaplanRowViews") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_page_views", + "anaplan_column_views", + "anaplan_line_items", + "anaplan_model", + "anaplan_row_views", + ] + + @property + def anaplan_page_views(self) -> Optional[List[AnaplanView]]: + return None if self.attributes is None else self.attributes.anaplan_page_views + + @anaplan_page_views.setter + def anaplan_page_views(self, anaplan_page_views: Optional[List[AnaplanView]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_page_views = anaplan_page_views + + @property + def anaplan_column_views(self) -> Optional[List[AnaplanView]]: + return None if self.attributes is None else self.attributes.anaplan_column_views + + @anaplan_column_views.setter + def anaplan_column_views(self, anaplan_column_views: Optional[List[AnaplanView]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_column_views = anaplan_column_views + + @property + def anaplan_line_items(self) -> Optional[List[AnaplanLineItem]]: + return None if self.attributes is None else self.attributes.anaplan_line_items + + @anaplan_line_items.setter + def anaplan_line_items(self, anaplan_line_items: Optional[List[AnaplanLineItem]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_line_items = anaplan_line_items + + @property + def anaplan_model(self) -> Optional[AnaplanModel]: + return None if self.attributes is None else self.attributes.anaplan_model + + @anaplan_model.setter + def anaplan_model(self, anaplan_model: Optional[AnaplanModel]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_model = anaplan_model + + @property + def anaplan_row_views(self) -> Optional[List[AnaplanView]]: + return None if self.attributes is None else self.attributes.anaplan_row_views + + @anaplan_row_views.setter + def anaplan_row_views(self, anaplan_row_views: Optional[List[AnaplanView]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_row_views = anaplan_row_views + + class Attributes(Anaplan.Attributes): + anaplan_page_views: Optional[List[AnaplanView]] = Field( + default=None, description="" + ) # relationship + anaplan_column_views: Optional[List[AnaplanView]] = Field( + default=None, description="" + ) # relationship + anaplan_line_items: Optional[List[AnaplanLineItem]] = Field( + default=None, description="" + ) # relationship + anaplan_model: Optional[AnaplanModel] = Field( + default=None, description="" + ) # relationship + anaplan_row_views: Optional[List[AnaplanView]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanDimension.Attributes = Field( + default_factory=lambda: AnaplanDimension.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_line_item import AnaplanLineItem # noqa +from .anaplan_model import AnaplanModel # noqa +from .anaplan_view import AnaplanView # noqa + +AnaplanDimension.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_line_item.py b/pyatlan/model/assets/anaplan_line_item.py new file mode 100644 index 00000000..78a74864 --- /dev/null +++ b/pyatlan/model/assets/anaplan_line_item.py @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import KeywordField, RelationField + +from .anaplan import Anaplan + + +class AnaplanLineItem(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanLineItem", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanLineItem": + raise ValueError("must be AnaplanLineItem") + return v + + def __setattr__(self, name, value): + if name in AnaplanLineItem._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_LINE_ITEM_FORMULA: ClassVar[KeywordField] = KeywordField( + "anaplanLineItemFormula", "anaplanLineItemFormula" + ) + """ + Formula of the AnaplanLineItem from the source system. + """ + + ANAPLAN_MODULE: ClassVar[RelationField] = RelationField("anaplanModule") + """ + TBC + """ + ANAPLAN_LISTS: ClassVar[RelationField] = RelationField("anaplanLists") + """ + TBC + """ + ANAPLAN_DIMENSIONS: ClassVar[RelationField] = RelationField("anaplanDimensions") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_line_item_formula", + "anaplan_module", + "anaplan_lists", + "anaplan_dimensions", + ] + + @property + def anaplan_line_item_formula(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_line_item_formula + ) + + @anaplan_line_item_formula.setter + def anaplan_line_item_formula(self, anaplan_line_item_formula: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_line_item_formula = anaplan_line_item_formula + + @property + def anaplan_module(self) -> Optional[AnaplanModule]: + return None if self.attributes is None else self.attributes.anaplan_module + + @anaplan_module.setter + def anaplan_module(self, anaplan_module: Optional[AnaplanModule]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_module = anaplan_module + + @property + def anaplan_lists(self) -> Optional[List[AnaplanList]]: + return None if self.attributes is None else self.attributes.anaplan_lists + + @anaplan_lists.setter + def anaplan_lists(self, anaplan_lists: Optional[List[AnaplanList]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_lists = anaplan_lists + + @property + def anaplan_dimensions(self) -> Optional[List[AnaplanDimension]]: + return None if self.attributes is None else self.attributes.anaplan_dimensions + + @anaplan_dimensions.setter + def anaplan_dimensions(self, anaplan_dimensions: Optional[List[AnaplanDimension]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_dimensions = anaplan_dimensions + + class Attributes(Anaplan.Attributes): + anaplan_line_item_formula: Optional[str] = Field(default=None, description="") + anaplan_module: Optional[AnaplanModule] = Field( + default=None, description="" + ) # relationship + anaplan_lists: Optional[List[AnaplanList]] = Field( + default=None, description="" + ) # relationship + anaplan_dimensions: Optional[List[AnaplanDimension]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanLineItem.Attributes = Field( + default_factory=lambda: AnaplanLineItem.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_dimension import AnaplanDimension # noqa +from .anaplan_list import AnaplanList # noqa +from .anaplan_module import AnaplanModule # noqa + +AnaplanLineItem.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_list.py b/pyatlan/model/assets/anaplan_list.py new file mode 100644 index 00000000..4d9aa566 --- /dev/null +++ b/pyatlan/model/assets/anaplan_list.py @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import NumericField, RelationField + +from .anaplan import Anaplan + + +class AnaplanList(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanList", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanList": + raise ValueError("must be AnaplanList") + return v + + def __setattr__(self, name, value): + if name in AnaplanList._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_LIST_ITEM_COUNT: ClassVar[NumericField] = NumericField( + "anaplanListItemCount", "anaplanListItemCount" + ) + """ + Item Count of the AnaplanList from the source system. + """ + + ANAPLAN_LINE_ITEMS: ClassVar[RelationField] = RelationField("anaplanLineItems") + """ + TBC + """ + ANAPLAN_MODEL: ClassVar[RelationField] = RelationField("anaplanModel") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_list_item_count", + "anaplan_line_items", + "anaplan_model", + ] + + @property + def anaplan_list_item_count(self) -> Optional[int]: + return ( + None if self.attributes is None else self.attributes.anaplan_list_item_count + ) + + @anaplan_list_item_count.setter + def anaplan_list_item_count(self, anaplan_list_item_count: Optional[int]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_list_item_count = anaplan_list_item_count + + @property + def anaplan_line_items(self) -> Optional[List[AnaplanLineItem]]: + return None if self.attributes is None else self.attributes.anaplan_line_items + + @anaplan_line_items.setter + def anaplan_line_items(self, anaplan_line_items: Optional[List[AnaplanLineItem]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_line_items = anaplan_line_items + + @property + def anaplan_model(self) -> Optional[AnaplanModel]: + return None if self.attributes is None else self.attributes.anaplan_model + + @anaplan_model.setter + def anaplan_model(self, anaplan_model: Optional[AnaplanModel]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_model = anaplan_model + + class Attributes(Anaplan.Attributes): + anaplan_list_item_count: Optional[int] = Field(default=None, description="") + anaplan_line_items: Optional[List[AnaplanLineItem]] = Field( + default=None, description="" + ) # relationship + anaplan_model: Optional[AnaplanModel] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanList.Attributes = Field( + default_factory=lambda: AnaplanList.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_line_item import AnaplanLineItem # noqa +from .anaplan_model import AnaplanModel # noqa + +AnaplanList.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_model.py b/pyatlan/model/assets/anaplan_model.py new file mode 100644 index 00000000..b4a4c42e --- /dev/null +++ b/pyatlan/model/assets/anaplan_model.py @@ -0,0 +1,144 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .anaplan import Anaplan + + +class AnaplanModel(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanModel", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanModel": + raise ValueError("must be AnaplanModel") + return v + + def __setattr__(self, name, value): + if name in AnaplanModel._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_WORKSPACE: ClassVar[RelationField] = RelationField("anaplanWorkspace") + """ + TBC + """ + ANAPLAN_MODULES: ClassVar[RelationField] = RelationField("anaplanModules") + """ + TBC + """ + ANAPLAN_PAGES: ClassVar[RelationField] = RelationField("anaplanPages") + """ + TBC + """ + ANAPLAN_LISTS: ClassVar[RelationField] = RelationField("anaplanLists") + """ + TBC + """ + ANAPLAN_DIMENSIONS: ClassVar[RelationField] = RelationField("anaplanDimensions") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_workspace", + "anaplan_modules", + "anaplan_pages", + "anaplan_lists", + "anaplan_dimensions", + ] + + @property + def anaplan_workspace(self) -> Optional[AnaplanWorkspace]: + return None if self.attributes is None else self.attributes.anaplan_workspace + + @anaplan_workspace.setter + def anaplan_workspace(self, anaplan_workspace: Optional[AnaplanWorkspace]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_workspace = anaplan_workspace + + @property + def anaplan_modules(self) -> Optional[List[AnaplanModule]]: + return None if self.attributes is None else self.attributes.anaplan_modules + + @anaplan_modules.setter + def anaplan_modules(self, anaplan_modules: Optional[List[AnaplanModule]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_modules = anaplan_modules + + @property + def anaplan_pages(self) -> Optional[List[AnaplanPage]]: + return None if self.attributes is None else self.attributes.anaplan_pages + + @anaplan_pages.setter + def anaplan_pages(self, anaplan_pages: Optional[List[AnaplanPage]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_pages = anaplan_pages + + @property + def anaplan_lists(self) -> Optional[List[AnaplanList]]: + return None if self.attributes is None else self.attributes.anaplan_lists + + @anaplan_lists.setter + def anaplan_lists(self, anaplan_lists: Optional[List[AnaplanList]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_lists = anaplan_lists + + @property + def anaplan_dimensions(self) -> Optional[List[AnaplanDimension]]: + return None if self.attributes is None else self.attributes.anaplan_dimensions + + @anaplan_dimensions.setter + def anaplan_dimensions(self, anaplan_dimensions: Optional[List[AnaplanDimension]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_dimensions = anaplan_dimensions + + class Attributes(Anaplan.Attributes): + anaplan_workspace: Optional[AnaplanWorkspace] = Field( + default=None, description="" + ) # relationship + anaplan_modules: Optional[List[AnaplanModule]] = Field( + default=None, description="" + ) # relationship + anaplan_pages: Optional[List[AnaplanPage]] = Field( + default=None, description="" + ) # relationship + anaplan_lists: Optional[List[AnaplanList]] = Field( + default=None, description="" + ) # relationship + anaplan_dimensions: Optional[List[AnaplanDimension]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanModel.Attributes = Field( + default_factory=lambda: AnaplanModel.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_dimension import AnaplanDimension # noqa +from .anaplan_list import AnaplanList # noqa +from .anaplan_module import AnaplanModule # noqa +from .anaplan_page import AnaplanPage # noqa +from .anaplan_workspace import AnaplanWorkspace # noqa + +AnaplanModel.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_module.py b/pyatlan/model/assets/anaplan_module.py new file mode 100644 index 00000000..f8db2ac9 --- /dev/null +++ b/pyatlan/model/assets/anaplan_module.py @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .anaplan import Anaplan + + +class AnaplanModule(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanModule", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanModule": + raise ValueError("must be AnaplanModule") + return v + + def __setattr__(self, name, value): + if name in AnaplanModule._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_VIEWS: ClassVar[RelationField] = RelationField("anaplanViews") + """ + TBC + """ + ANAPLAN_LINE_ITEMS: ClassVar[RelationField] = RelationField("anaplanLineItems") + """ + TBC + """ + ANAPLAN_MODEL: ClassVar[RelationField] = RelationField("anaplanModel") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_views", + "anaplan_line_items", + "anaplan_model", + ] + + @property + def anaplan_views(self) -> Optional[List[AnaplanView]]: + return None if self.attributes is None else self.attributes.anaplan_views + + @anaplan_views.setter + def anaplan_views(self, anaplan_views: Optional[List[AnaplanView]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_views = anaplan_views + + @property + def anaplan_line_items(self) -> Optional[List[AnaplanLineItem]]: + return None if self.attributes is None else self.attributes.anaplan_line_items + + @anaplan_line_items.setter + def anaplan_line_items(self, anaplan_line_items: Optional[List[AnaplanLineItem]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_line_items = anaplan_line_items + + @property + def anaplan_model(self) -> Optional[AnaplanModel]: + return None if self.attributes is None else self.attributes.anaplan_model + + @anaplan_model.setter + def anaplan_model(self, anaplan_model: Optional[AnaplanModel]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_model = anaplan_model + + class Attributes(Anaplan.Attributes): + anaplan_views: Optional[List[AnaplanView]] = Field( + default=None, description="" + ) # relationship + anaplan_line_items: Optional[List[AnaplanLineItem]] = Field( + default=None, description="" + ) # relationship + anaplan_model: Optional[AnaplanModel] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanModule.Attributes = Field( + default_factory=lambda: AnaplanModule.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_line_item import AnaplanLineItem # noqa +from .anaplan_model import AnaplanModel # noqa +from .anaplan_view import AnaplanView # noqa + +AnaplanModule.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_page.py b/pyatlan/model/assets/anaplan_page.py new file mode 100644 index 00000000..cdd3a2cb --- /dev/null +++ b/pyatlan/model/assets/anaplan_page.py @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import KeywordField, RelationField + +from .anaplan import Anaplan + + +class AnaplanPage(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanPage", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanPage": + raise ValueError("must be AnaplanPage") + return v + + def __setattr__(self, name, value): + if name in AnaplanPage._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_APP_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanAppQualifiedName", "anaplanAppQualifiedName" + ) + """ + Unique name of the AnaplanApp asset that contains this asset. + """ + ANAPLAN_PAGE_CATEGORY_NAME: ClassVar[KeywordField] = KeywordField( + "anaplanPageCategoryName", "anaplanPageCategoryName" + ) + """ + Category Name of the AnaplanPage from the source system. + """ + ANAPLAN_PAGE_TYPE: ClassVar[KeywordField] = KeywordField( + "anaplanPageType", "anaplanPageType" + ) + """ + Type of the AnaplanPage from the source system. + """ + + ANAPLAN_MODELS: ClassVar[RelationField] = RelationField("anaplanModels") + """ + TBC + """ + ANAPLAN_APP: ClassVar[RelationField] = RelationField("anaplanApp") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_app_qualified_name", + "anaplan_page_category_name", + "anaplan_page_type", + "anaplan_models", + "anaplan_app", + ] + + @property + def anaplan_app_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_app_qualified_name + ) + + @anaplan_app_qualified_name.setter + def anaplan_app_qualified_name(self, anaplan_app_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_app_qualified_name = anaplan_app_qualified_name + + @property + def anaplan_page_category_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_page_category_name + ) + + @anaplan_page_category_name.setter + def anaplan_page_category_name(self, anaplan_page_category_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_page_category_name = anaplan_page_category_name + + @property + def anaplan_page_type(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.anaplan_page_type + + @anaplan_page_type.setter + def anaplan_page_type(self, anaplan_page_type: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_page_type = anaplan_page_type + + @property + def anaplan_models(self) -> Optional[List[AnaplanModel]]: + return None if self.attributes is None else self.attributes.anaplan_models + + @anaplan_models.setter + def anaplan_models(self, anaplan_models: Optional[List[AnaplanModel]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_models = anaplan_models + + @property + def anaplan_app(self) -> Optional[AnaplanApp]: + return None if self.attributes is None else self.attributes.anaplan_app + + @anaplan_app.setter + def anaplan_app(self, anaplan_app: Optional[AnaplanApp]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_app = anaplan_app + + class Attributes(Anaplan.Attributes): + anaplan_app_qualified_name: Optional[str] = Field(default=None, description="") + anaplan_page_category_name: Optional[str] = Field(default=None, description="") + anaplan_page_type: Optional[str] = Field(default=None, description="") + anaplan_models: Optional[List[AnaplanModel]] = Field( + default=None, description="" + ) # relationship + anaplan_app: Optional[AnaplanApp] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanPage.Attributes = Field( + default_factory=lambda: AnaplanPage.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_app import AnaplanApp # noqa +from .anaplan_model import AnaplanModel # noqa + +AnaplanPage.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_view.py b/pyatlan/model/assets/anaplan_view.py new file mode 100644 index 00000000..743d942f --- /dev/null +++ b/pyatlan/model/assets/anaplan_view.py @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .anaplan import Anaplan + + +class AnaplanView(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanView", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanView": + raise ValueError("must be AnaplanView") + return v + + def __setattr__(self, name, value): + if name in AnaplanView._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_MODULE: ClassVar[RelationField] = RelationField("anaplanModule") + """ + TBC + """ + ANAPLAN_PAGE_DIMENSIONS: ClassVar[RelationField] = RelationField( + "anaplanPageDimensions" + ) + """ + TBC + """ + ANAPLAN_ROW_DIMENSIONS: ClassVar[RelationField] = RelationField( + "anaplanRowDimensions" + ) + """ + TBC + """ + ANAPLAN_COLUMN_DIMENSIONS: ClassVar[RelationField] = RelationField( + "anaplanColumnDimensions" + ) + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_module", + "anaplan_page_dimensions", + "anaplan_row_dimensions", + "anaplan_column_dimensions", + ] + + @property + def anaplan_module(self) -> Optional[AnaplanModule]: + return None if self.attributes is None else self.attributes.anaplan_module + + @anaplan_module.setter + def anaplan_module(self, anaplan_module: Optional[AnaplanModule]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_module = anaplan_module + + @property + def anaplan_page_dimensions(self) -> Optional[List[AnaplanDimension]]: + return ( + None if self.attributes is None else self.attributes.anaplan_page_dimensions + ) + + @anaplan_page_dimensions.setter + def anaplan_page_dimensions( + self, anaplan_page_dimensions: Optional[List[AnaplanDimension]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_page_dimensions = anaplan_page_dimensions + + @property + def anaplan_row_dimensions(self) -> Optional[List[AnaplanDimension]]: + return ( + None if self.attributes is None else self.attributes.anaplan_row_dimensions + ) + + @anaplan_row_dimensions.setter + def anaplan_row_dimensions( + self, anaplan_row_dimensions: Optional[List[AnaplanDimension]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_row_dimensions = anaplan_row_dimensions + + @property + def anaplan_column_dimensions(self) -> Optional[List[AnaplanDimension]]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_column_dimensions + ) + + @anaplan_column_dimensions.setter + def anaplan_column_dimensions( + self, anaplan_column_dimensions: Optional[List[AnaplanDimension]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_column_dimensions = anaplan_column_dimensions + + class Attributes(Anaplan.Attributes): + anaplan_module: Optional[AnaplanModule] = Field( + default=None, description="" + ) # relationship + anaplan_page_dimensions: Optional[List[AnaplanDimension]] = Field( + default=None, description="" + ) # relationship + anaplan_row_dimensions: Optional[List[AnaplanDimension]] = Field( + default=None, description="" + ) # relationship + anaplan_column_dimensions: Optional[List[AnaplanDimension]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanView.Attributes = Field( + default_factory=lambda: AnaplanView.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_dimension import AnaplanDimension # noqa +from .anaplan_module import AnaplanModule # noqa + +AnaplanView.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/anaplan_workspace.py b/pyatlan/model/assets/anaplan_workspace.py new file mode 100644 index 00000000..d485e0c9 --- /dev/null +++ b/pyatlan/model/assets/anaplan_workspace.py @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import NumericField, RelationField + +from .anaplan import Anaplan + + +class AnaplanWorkspace(Anaplan): + """Description""" + + type_name: str = Field(default="AnaplanWorkspace", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AnaplanWorkspace": + raise ValueError("must be AnaplanWorkspace") + return v + + def __setattr__(self, name, value): + if name in AnaplanWorkspace._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + ANAPLAN_WORKSPACE_CURRENT_SIZE: ClassVar[NumericField] = NumericField( + "anaplanWorkspaceCurrentSize", "anaplanWorkspaceCurrentSize" + ) + """ + Current Size of the AnaplanWorkspace from the source system, estimated in MB. + """ + ANAPLAN_WORKSPACE_ALLOWANCE_SIZE: ClassVar[NumericField] = NumericField( + "anaplanWorkspaceAllowanceSize", "anaplanWorkspaceAllowanceSize" + ) + """ + Alloted Size quota for the AnaplanWorkspace from the source system, estimated in MB. + """ + + ANAPLAN_MODELS: ClassVar[RelationField] = RelationField("anaplanModels") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "anaplan_workspace_current_size", + "anaplan_workspace_allowance_size", + "anaplan_models", + ] + + @property + def anaplan_workspace_current_size(self) -> Optional[int]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_workspace_current_size + ) + + @anaplan_workspace_current_size.setter + def anaplan_workspace_current_size( + self, anaplan_workspace_current_size: Optional[int] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_workspace_current_size = anaplan_workspace_current_size + + @property + def anaplan_workspace_allowance_size(self) -> Optional[int]: + return ( + None + if self.attributes is None + else self.attributes.anaplan_workspace_allowance_size + ) + + @anaplan_workspace_allowance_size.setter + def anaplan_workspace_allowance_size( + self, anaplan_workspace_allowance_size: Optional[int] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_workspace_allowance_size = ( + anaplan_workspace_allowance_size + ) + + @property + def anaplan_models(self) -> Optional[List[AnaplanModel]]: + return None if self.attributes is None else self.attributes.anaplan_models + + @anaplan_models.setter + def anaplan_models(self, anaplan_models: Optional[List[AnaplanModel]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.anaplan_models = anaplan_models + + class Attributes(Anaplan.Attributes): + anaplan_workspace_current_size: Optional[int] = Field( + default=None, description="" + ) + anaplan_workspace_allowance_size: Optional[int] = Field( + default=None, description="" + ) + anaplan_models: Optional[List[AnaplanModel]] = Field( + default=None, description="" + ) # relationship + + attributes: AnaplanWorkspace.Attributes = Field( + default_factory=lambda: AnaplanWorkspace.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .anaplan_model import AnaplanModel # noqa + +AnaplanWorkspace.Attributes.update_forward_refs() From 60ae02396004d81f36e83e740e3b71bf439ea31d Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 17:07:41 +0530 Subject: [PATCH 12/66] anaplan creator methods and generator templates --- .../methods/asset/anaplan_app.jinja2 | 11 +++ .../methods/asset/anaplan_dimension.jinja2 | 38 +++++++++ .../methods/asset/anaplan_line_item.jinja2 | 38 +++++++++ .../methods/asset/anaplan_list.jinja2 | 38 +++++++++ .../methods/asset/anaplan_model.jinja2 | 38 +++++++++ .../methods/asset/anaplan_module.jinja2 | 38 +++++++++ .../methods/asset/anaplan_page.jinja2 | 38 +++++++++ .../methods/asset/anaplan_view.jinja2 | 38 +++++++++ .../methods/asset/anaplan_workspace.jinja2 | 11 +++ .../methods/attribute/anaplan_app.jinja2 | 17 ++++ .../attribute/anaplan_dimension.jinja2 | 38 +++++++++ .../attribute/anaplan_line_item.jinja2 | 41 +++++++++ .../methods/attribute/anaplan_list.jinja2 | 38 +++++++++ .../methods/attribute/anaplan_model.jinja2 | 34 ++++++++ .../methods/attribute/anaplan_module.jinja2 | 38 +++++++++ .../methods/attribute/anaplan_page.jinja2 | 31 +++++++ .../methods/attribute/anaplan_view.jinja2 | 41 +++++++++ .../attribute/anaplan_workspace.jinja2 | 17 ++++ pyatlan/model/assets/anaplan_app.py | 30 +++++++ pyatlan/model/assets/anaplan_dimension.py | 80 ++++++++++++++++- pyatlan/model/assets/anaplan_line_item.py | 85 ++++++++++++++++++- pyatlan/model/assets/anaplan_list.py | 80 ++++++++++++++++- pyatlan/model/assets/anaplan_model.py | 78 ++++++++++++++++- pyatlan/model/assets/anaplan_module.py | 80 ++++++++++++++++- pyatlan/model/assets/anaplan_page.py | 73 +++++++++++++++- pyatlan/model/assets/anaplan_view.py | 85 ++++++++++++++++++- pyatlan/model/assets/anaplan_workspace.py | 30 +++++++ pyatlan/model/constants.py | 9 ++ pyatlan/model/enums.py | 1 + pyatlan/model/typedef.py | 9 ++ 30 files changed, 1216 insertions(+), 7 deletions(-) create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_app.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_dimension.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_line_item.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_list.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_model.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_module.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_page.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_view.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/anaplan_workspace.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_app.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_dimension.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_line_item.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_list.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_model.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_module.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_page.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_view.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/anaplan_workspace.jinja2 diff --git a/pyatlan/generator/templates/methods/asset/anaplan_app.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_app.jinja2 new file mode 100644 index 00000000..2ff3e6d2 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_app.jinja2 @@ -0,0 +1,11 @@ + + @classmethod + @init_guid + def creator(cls, *, name: str, connection_qualified_name: str) -> AnaplanApp: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + attributes = AnaplanApp.Attributes.create( + name=name, connection_qualified_name=connection_qualified_name + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_dimension.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_dimension.jinja2 new file mode 100644 index 00000000..3d3dafd0 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_dimension.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanDimension: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanDimension: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanDimension: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanDimension.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_line_item.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_line_item.jinja2 new file mode 100644 index 00000000..c669a5b4 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_line_item.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + ) -> AnaplanLineItem: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanLineItem: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanLineItem: + validate_required_fields( + ["name", "module_qualified_name"], [name, module_qualified_name] + ) + attributes = AnaplanLineItem.Attributes.create( + name=name, + module_qualified_name=module_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_list.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_list.jinja2 new file mode 100644 index 00000000..641ccb8a --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_list.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanList: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanList: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanList: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanList.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_model.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_model.jinja2 new file mode 100644 index 00000000..75ba7529 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_model.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + ) -> AnaplanModel: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanModel: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModel: + validate_required_fields( + ["name", "workspace_qualified_name"], [name, workspace_qualified_name] + ) + attributes = AnaplanModel.Attributes.create( + name=name, + workspace_qualified_name=workspace_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_module.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_module.jinja2 new file mode 100644 index 00000000..22410396 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_module.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanModule: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanModule: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModule: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanModule.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_page.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_page.jinja2 new file mode 100644 index 00000000..d6109f5f --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_page.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + app_qualified_name: str, + ) -> AnaplanPage: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanPage: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanPage: + validate_required_fields( + ["name", "app_qualified_name"], [name, app_qualified_name] + ) + attributes = AnaplanPage.Attributes.create( + name=name, + app_qualified_name=app_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_view.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_view.jinja2 new file mode 100644 index 00000000..0771014d --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_view.jinja2 @@ -0,0 +1,38 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + ) -> AnaplanView: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanView: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanView: + validate_required_fields( + ["name", "module_qualified_name"], [name, module_qualified_name] + ) + attributes = AnaplanView.Attributes.create( + name=name, + module_qualified_name=module_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/asset/anaplan_workspace.jinja2 b/pyatlan/generator/templates/methods/asset/anaplan_workspace.jinja2 new file mode 100644 index 00000000..2179200a --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/anaplan_workspace.jinja2 @@ -0,0 +1,11 @@ + + @classmethod + @init_guid + def creator(cls, *, name: str, connection_qualified_name: str) -> AnaplanWorkspace: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + attributes = AnaplanWorkspace.Attributes.create( + name=name, connection_qualified_name=connection_qualified_name + ) + return cls(attributes=attributes) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_app.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_app.jinja2 new file mode 100644 index 00000000..f98fd3a6 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_app.jinja2 @@ -0,0 +1,17 @@ + + @classmethod + @init_guid + def create( + cls, *, name: str, connection_qualified_name: str + ) -> AnaplanApp.Attributes: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + return AnaplanApp.Attributes( + name=name, + qualified_name=f"{connection_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name, + connector_name=AtlanConnectorType.get_connector_name( + connection_qualified_name + ), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_dimension.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_dimension.jinja2 new file mode 100644 index 00000000..d9344fa8 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_dimension.jinja2 @@ -0,0 +1,38 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanDimension.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanDimension.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_line_item.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_line_item.jinja2 new file mode 100644 index 00000000..4b8acdb7 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_line_item.jinja2 @@ -0,0 +1,41 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanLineItem.Attributes: + validate_required_fields( + ["name", "module_qualified_name"], + [name, module_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + module_qualified_name, "module_qualified_name", 6 + ) + + fields = module_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + module_name = fields[5] + + return AnaplanLineItem.Attributes( + name=name, + qualified_name=f"{module_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}/{fields[4]}", + anaplan_model_name=model_name, + anaplan_module_qualified_name=module_qualified_name, + anaplan_module_name=module_name, + anaplan_module=AnaplanModule.ref_by_qualified_name(module_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_list.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_list.jinja2 new file mode 100644 index 00000000..4d314a4f --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_list.jinja2 @@ -0,0 +1,38 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanList.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanList.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_model.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_model.jinja2 new file mode 100644 index 00000000..f205ccb3 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_model.jinja2 @@ -0,0 +1,34 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModel.Attributes: + validate_required_fields( + ["name", "workspace_qualified_name"], + [name, workspace_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + workspace_qualified_name, "workspace_qualified_name", 4 + ) + + workspace_name = workspace_qualified_name.split("/")[3] + + return AnaplanModel.Attributes( + name=name, + qualified_name=f"{workspace_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=workspace_qualified_name, + anaplan_workspace_name=workspace_name, + anaplan_workspace=AnaplanWorkspace.ref_by_qualified_name(workspace_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_module.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_module.jinja2 new file mode 100644 index 00000000..ca07870c --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_module.jinja2 @@ -0,0 +1,38 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModule.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanModule.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_page.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_page.jinja2 new file mode 100644 index 00000000..2dbb21c9 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_page.jinja2 @@ -0,0 +1,31 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanPage.Attributes: + validate_required_fields( + ["name", "app_qualified_name"], + [name, app_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + app_qualified_name, "app_qualified_name", 4 + ) + + return AnaplanPage.Attributes( + name=name, + qualified_name=f"{app_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_app_qualified_name=app_qualified_name, + anaplan_app=AnaplanApp.ref_by_qualified_name(app_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_view.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_view.jinja2 new file mode 100644 index 00000000..111964ff --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_view.jinja2 @@ -0,0 +1,41 @@ + + @classmethod + @init_guid + def create( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanView.Attributes: + validate_required_fields( + ["name", "module_qualified_name"], + [name, module_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + module_qualified_name, "module_qualified_name", 6 + ) + + fields = module_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + module_name = fields[5] + + return AnaplanView.Attributes( + name=name, + qualified_name=f"{module_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}/{fields[4]}", + anaplan_model_name=model_name, + anaplan_module_qualified_name=module_qualified_name, + anaplan_module_name=module_name, + anaplan_module=AnaplanModule.ref_by_qualified_name(module_qualified_name), + ) diff --git a/pyatlan/generator/templates/methods/attribute/anaplan_workspace.jinja2 b/pyatlan/generator/templates/methods/attribute/anaplan_workspace.jinja2 new file mode 100644 index 00000000..c9b50977 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/anaplan_workspace.jinja2 @@ -0,0 +1,17 @@ + + @classmethod + @init_guid + def create( + cls, *, name: str, connection_qualified_name: str + ) -> AnaplanWorkspace.Attributes: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + return AnaplanWorkspace.Attributes( + name=name, + qualified_name=f"{connection_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name, + connector_name=AtlanConnectorType.get_connector_name( + connection_qualified_name + ), + ) diff --git a/pyatlan/model/assets/anaplan_app.py b/pyatlan/model/assets/anaplan_app.py index 98cd508b..e7cc9212 100644 --- a/pyatlan/model/assets/anaplan_app.py +++ b/pyatlan/model/assets/anaplan_app.py @@ -8,7 +8,9 @@ from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,17 @@ class AnaplanApp(Anaplan): """Description""" + @classmethod + @init_guid + def creator(cls, *, name: str, connection_qualified_name: str) -> AnaplanApp: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + attributes = AnaplanApp.Attributes.create( + name=name, connection_qualified_name=connection_qualified_name + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanApp", allow_mutation=False) @validator("type_name") @@ -53,6 +66,23 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, *, name: str, connection_qualified_name: str + ) -> AnaplanApp.Attributes: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + return AnaplanApp.Attributes( + name=name, + qualified_name=f"{connection_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name, + connector_name=AtlanConnectorType.get_connector_name( + connection_qualified_name + ), + ) + attributes: AnaplanApp.Attributes = Field( default_factory=lambda: AnaplanApp.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_dimension.py b/pyatlan/model/assets/anaplan_dimension.py index aaf61daf..7bb8621f 100644 --- a/pyatlan/model/assets/anaplan_dimension.py +++ b/pyatlan/model/assets/anaplan_dimension.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanDimension(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanDimension: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanDimension: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanDimension: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanDimension.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanDimension", allow_mutation=False) @validator("type_name") @@ -125,6 +165,44 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanDimension.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanDimension.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) + attributes: AnaplanDimension.Attributes = Field( default_factory=lambda: AnaplanDimension.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_line_item.py b/pyatlan/model/assets/anaplan_line_item.py index 78a74864..b22fe1e7 100644 --- a/pyatlan/model/assets/anaplan_line_item.py +++ b/pyatlan/model/assets/anaplan_line_item.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import KeywordField, RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanLineItem(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + ) -> AnaplanLineItem: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanLineItem: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanLineItem: + validate_required_fields( + ["name", "module_qualified_name"], [name, module_qualified_name] + ) + attributes = AnaplanLineItem.Attributes.create( + name=name, + module_qualified_name=module_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanLineItem", allow_mutation=False) @validator("type_name") @@ -112,6 +152,49 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanLineItem.Attributes: + validate_required_fields( + ["name", "module_qualified_name"], + [name, module_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + module_qualified_name, "module_qualified_name", 6 + ) + + fields = module_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + module_name = fields[5] + + return AnaplanLineItem.Attributes( + name=name, + qualified_name=f"{module_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}/{fields[4]}", + anaplan_model_name=model_name, + anaplan_module_qualified_name=module_qualified_name, + anaplan_module_name=module_name, + anaplan_module=AnaplanModule.ref_by_qualified_name( + module_qualified_name + ), + ) + attributes: AnaplanLineItem.Attributes = Field( default_factory=lambda: AnaplanLineItem.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_list.py b/pyatlan/model/assets/anaplan_list.py index 4d9aa566..83755036 100644 --- a/pyatlan/model/assets/anaplan_list.py +++ b/pyatlan/model/assets/anaplan_list.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import NumericField, RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanList(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanList: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanList: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanList: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanList.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanList", allow_mutation=False) @validator("type_name") @@ -92,6 +132,44 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanList.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanList.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) + attributes: AnaplanList.Attributes = Field( default_factory=lambda: AnaplanList.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_model.py b/pyatlan/model/assets/anaplan_model.py index b4a4c42e..33be8dbc 100644 --- a/pyatlan/model/assets/anaplan_model.py +++ b/pyatlan/model/assets/anaplan_model.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanModel(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + ) -> AnaplanModel: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanModel: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModel: + validate_required_fields( + ["name", "workspace_qualified_name"], [name, workspace_qualified_name] + ) + attributes = AnaplanModel.Attributes.create( + name=name, + workspace_qualified_name=workspace_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanModel", allow_mutation=False) @validator("type_name") @@ -125,6 +165,42 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + workspace_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModel.Attributes: + validate_required_fields( + ["name", "workspace_qualified_name"], + [name, workspace_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + workspace_qualified_name, "workspace_qualified_name", 4 + ) + + workspace_name = workspace_qualified_name.split("/")[3] + + return AnaplanModel.Attributes( + name=name, + qualified_name=f"{workspace_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=workspace_qualified_name, + anaplan_workspace_name=workspace_name, + anaplan_workspace=AnaplanWorkspace.ref_by_qualified_name( + workspace_qualified_name + ), + ) + attributes: AnaplanModel.Attributes = Field( default_factory=lambda: AnaplanModel.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_module.py b/pyatlan/model/assets/anaplan_module.py index f8db2ac9..98963bb8 100644 --- a/pyatlan/model/assets/anaplan_module.py +++ b/pyatlan/model/assets/anaplan_module.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanModule(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + ) -> AnaplanModule: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanModule: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModule: + validate_required_fields( + ["name", "model_qualified_name"], [name, model_qualified_name] + ) + attributes = AnaplanModule.Attributes.create( + name=name, + model_qualified_name=model_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanModule", allow_mutation=False) @validator("type_name") @@ -89,6 +129,44 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + model_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanModule.Attributes: + validate_required_fields( + ["name", "model_qualified_name"], + [name, model_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + model_qualified_name, "model_qualified_name", 5 + ) + + fields = model_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + + return AnaplanModule.Attributes( + name=name, + qualified_name=f"{model_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=model_qualified_name, + anaplan_model_name=model_name, + anaplan_model=AnaplanModel.ref_by_qualified_name(model_qualified_name), + ) + attributes: AnaplanModule.Attributes = Field( default_factory=lambda: AnaplanModule.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_page.py b/pyatlan/model/assets/anaplan_page.py index cdd3a2cb..3c48a903 100644 --- a/pyatlan/model/assets/anaplan_page.py +++ b/pyatlan/model/assets/anaplan_page.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import KeywordField, RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanPage(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + app_qualified_name: str, + ) -> AnaplanPage: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanPage: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanPage: + validate_required_fields( + ["name", "app_qualified_name"], [name, app_qualified_name] + ) + attributes = AnaplanPage.Attributes.create( + name=name, + app_qualified_name=app_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanPage", allow_mutation=False) @validator("type_name") @@ -134,6 +174,37 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + app_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanPage.Attributes: + validate_required_fields( + ["name", "app_qualified_name"], + [name, app_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + app_qualified_name, "app_qualified_name", 4 + ) + + return AnaplanPage.Attributes( + name=name, + qualified_name=f"{app_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_app_qualified_name=app_qualified_name, + anaplan_app=AnaplanApp.ref_by_qualified_name(app_qualified_name), + ) + attributes: AnaplanPage.Attributes = Field( default_factory=lambda: AnaplanPage.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_view.py b/pyatlan/model/assets/anaplan_view.py index 743d942f..42a30ade 100644 --- a/pyatlan/model/assets/anaplan_view.py +++ b/pyatlan/model/assets/anaplan_view.py @@ -4,11 +4,13 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,44 @@ class AnaplanView(Anaplan): """Description""" + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + ) -> AnaplanView: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: str, + ) -> AnaplanView: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanView: + validate_required_fields( + ["name", "module_qualified_name"], [name, module_qualified_name] + ) + attributes = AnaplanView.Attributes.create( + name=name, + module_qualified_name=module_qualified_name, + connection_qualified_name=connection_qualified_name, + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanView", allow_mutation=False) @validator("type_name") @@ -127,6 +167,49 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, + *, + name: str, + module_qualified_name: str, + connection_qualified_name: Optional[str] = None, + ) -> AnaplanView.Attributes: + validate_required_fields( + ["name", "module_qualified_name"], + [name, module_qualified_name], + ) + if connection_qualified_name: + connector_name = AtlanConnectorType.get_connector_name( + connection_qualified_name + ) + else: + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + module_qualified_name, "module_qualified_name", 6 + ) + + fields = module_qualified_name.split("/") + workspace_name = fields[3] + model_name = fields[4] + module_name = fields[5] + + return AnaplanView.Attributes( + name=name, + qualified_name=f"{module_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name or connection_qn, + connector_name=connector_name, + anaplan_workspace_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}", + anaplan_workspace_name=workspace_name, + anaplan_model_qualified_name=f"{fields[0]}/{fields[1]}/{fields[2]}/{fields[3]}/{fields[4]}", + anaplan_model_name=model_name, + anaplan_module_qualified_name=module_qualified_name, + anaplan_module_name=module_name, + anaplan_module=AnaplanModule.ref_by_qualified_name( + module_qualified_name + ), + ) + attributes: AnaplanView.Attributes = Field( default_factory=lambda: AnaplanView.Attributes(), description=( diff --git a/pyatlan/model/assets/anaplan_workspace.py b/pyatlan/model/assets/anaplan_workspace.py index d485e0c9..bc4ee51e 100644 --- a/pyatlan/model/assets/anaplan_workspace.py +++ b/pyatlan/model/assets/anaplan_workspace.py @@ -8,7 +8,9 @@ from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import NumericField, RelationField +from pyatlan.utils import init_guid, validate_required_fields from .anaplan import Anaplan @@ -16,6 +18,17 @@ class AnaplanWorkspace(Anaplan): """Description""" + @classmethod + @init_guid + def creator(cls, *, name: str, connection_qualified_name: str) -> AnaplanWorkspace: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + attributes = AnaplanWorkspace.Attributes.create( + name=name, connection_qualified_name=connection_qualified_name + ) + return cls(attributes=attributes) + type_name: str = Field(default="AnaplanWorkspace", allow_mutation=False) @validator("type_name") @@ -108,6 +121,23 @@ class Attributes(Anaplan.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def create( + cls, *, name: str, connection_qualified_name: str + ) -> AnaplanWorkspace.Attributes: + validate_required_fields( + ["name", "connection_qualified_name"], [name, connection_qualified_name] + ) + return AnaplanWorkspace.Attributes( + name=name, + qualified_name=f"{connection_qualified_name}/{name}", + connection_qualified_name=connection_qualified_name, + connector_name=AtlanConnectorType.get_connector_name( + connection_qualified_name + ), + ) + attributes: AnaplanWorkspace.Attributes = Field( default_factory=lambda: AnaplanWorkspace.Attributes(), description=( diff --git a/pyatlan/model/constants.py b/pyatlan/model/constants.py index 2bfdc19a..34ec484f 100644 --- a/pyatlan/model/constants.py +++ b/pyatlan/model/constants.py @@ -20,6 +20,15 @@ "ADLSAccount", "ADLSContainer", "ADLSObject", + "AnaplanPage", + "AnaplanList", + "AnaplanLineItem", + "AnaplanWorkspace", + "AnaplanModule", + "AnaplanModel", + "AnaplanApp", + "AnaplanDimension", + "AnaplanView", "APIField", "APIObject", "APIPath", diff --git a/pyatlan/model/enums.py b/pyatlan/model/enums.py index e36ebde0..37367490 100644 --- a/pyatlan/model/enums.py +++ b/pyatlan/model/enums.py @@ -337,6 +337,7 @@ def get_connector_name( IBM_DB2 = ("ibmdb2", AtlanConnectionCategory.DATABASE) APP = ("app", AtlanConnectionCategory.APP) BIGID = ("bigid", AtlanConnectionCategory.SAAS) + ANAPLAN = ("anaplan", AtlanConnectionCategory.BI) class AtlanCustomAttributePrimitiveType(str, Enum): diff --git a/pyatlan/model/typedef.py b/pyatlan/model/typedef.py index 60a8b926..babee529 100644 --- a/pyatlan/model/typedef.py +++ b/pyatlan/model/typedef.py @@ -30,6 +30,15 @@ "ADLSAccount", "ADLSContainer", "ADLSObject", + "AnaplanPage", + "AnaplanList", + "AnaplanLineItem", + "AnaplanWorkspace", + "AnaplanModule", + "AnaplanModel", + "AnaplanApp", + "AnaplanDimension", + "AnaplanView", "APIObject", "APIQuery", "APIField", From 1fb0228aa13adb1148b59dd70f071382aa3f1c28 Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 19:49:05 +0530 Subject: [PATCH 13/66] anaplan unit test --- tests/unit/model/anaplan_app_test.py | 69 +++++++++++++++++++++ tests/unit/model/anaplan_dimension_test.py | 72 ++++++++++++++++++++++ tests/unit/model/anaplan_line_item_test.py | 72 ++++++++++++++++++++++ tests/unit/model/anaplan_list_test.py | 70 +++++++++++++++++++++ tests/unit/model/anaplan_model_test.py | 70 +++++++++++++++++++++ tests/unit/model/anaplan_module_test.py | 70 +++++++++++++++++++++ tests/unit/model/anaplan_page_test.py | 70 +++++++++++++++++++++ tests/unit/model/anaplan_view_test.py | 70 +++++++++++++++++++++ tests/unit/model/anaplan_workspace_test.py | 71 +++++++++++++++++++++ tests/unit/model/constants.py | 28 +++++++++ tests/unit/test_model.py | 18 ++++++ 11 files changed, 680 insertions(+) create mode 100644 tests/unit/model/anaplan_app_test.py create mode 100644 tests/unit/model/anaplan_dimension_test.py create mode 100644 tests/unit/model/anaplan_line_item_test.py create mode 100644 tests/unit/model/anaplan_list_test.py create mode 100644 tests/unit/model/anaplan_model_test.py create mode 100644 tests/unit/model/anaplan_module_test.py create mode 100644 tests/unit/model/anaplan_page_test.py create mode 100644 tests/unit/model/anaplan_view_test.py create mode 100644 tests/unit/model/anaplan_workspace_test.py diff --git a/tests/unit/model/anaplan_app_test.py b/tests/unit/model/anaplan_app_test.py new file mode 100644 index 00000000..cfbd541a --- /dev/null +++ b/tests/unit/model/anaplan_app_test.py @@ -0,0 +1,69 @@ +import pytest + +from pyatlan.model.assets import AnaplanApp +from tests.unit.model.constants import ( + ANAPLAN_APP_NAME, + ANAPLAN_APP_QUALIFIED_NAME, + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_APP_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanApp.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanApp.creator( + name=ANAPLAN_APP_NAME, + connection_qualified_name=ANAPLAN_CONNECTION_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_APP_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_APP_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_CONNECTION_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_APP_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanApp.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanApp.create_for_modification( + qualified_name=ANAPLAN_APP_QUALIFIED_NAME, name=ANAPLAN_APP_NAME + ) + + assert sut.qualified_name == ANAPLAN_APP_QUALIFIED_NAME + assert sut.name == ANAPLAN_APP_NAME + + +def test_trim_to_required(): + sut = AnaplanApp.create_for_modification( + name=ANAPLAN_APP_NAME, qualified_name=ANAPLAN_APP_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_APP_NAME + assert sut.qualified_name == ANAPLAN_APP_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_dimension_test.py b/tests/unit/model/anaplan_dimension_test.py new file mode 100644 index 00000000..94ed061b --- /dev/null +++ b/tests/unit/model/anaplan_dimension_test.py @@ -0,0 +1,72 @@ +import pytest + +from pyatlan.model.assets import AnaplanDimension +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_DIMENSION_NAME, + ANAPLAN_DIMENSION_QUALIFIED_NAME, + ANAPLAN_MODEL_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_DIMENSION_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanDimension.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanDimension.creator( + name=ANAPLAN_DIMENSION_NAME, + model_qualified_name=ANAPLAN_MODEL_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_DIMENSION_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_DIMENSION_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_MODEL_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_DIMENSION_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanDimension.create_for_modification( + qualified_name=qualified_name, name=name + ) + + +def test_create_for_modification(): + sut = AnaplanDimension.create_for_modification( + qualified_name=ANAPLAN_DIMENSION_QUALIFIED_NAME, name=ANAPLAN_DIMENSION_NAME + ) + + assert sut.qualified_name == ANAPLAN_DIMENSION_QUALIFIED_NAME + assert sut.name == ANAPLAN_DIMENSION_NAME + + +def test_trim_to_required(): + sut = AnaplanDimension.create_for_modification( + name=ANAPLAN_DIMENSION_NAME, qualified_name=ANAPLAN_DIMENSION_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_DIMENSION_NAME + assert sut.qualified_name == ANAPLAN_DIMENSION_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_line_item_test.py b/tests/unit/model/anaplan_line_item_test.py new file mode 100644 index 00000000..2a145b5f --- /dev/null +++ b/tests/unit/model/anaplan_line_item_test.py @@ -0,0 +1,72 @@ +import pytest + +from pyatlan.model.assets import AnaplanLineItem +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_LINE_ITEM_NAME, + ANAPLAN_LINE_ITEM_QUALIFIED_NAME, + ANAPLAN_MODULE_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_LINE_ITEM_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanLineItem.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanLineItem.creator( + name=ANAPLAN_LINE_ITEM_NAME, + module_qualified_name=ANAPLAN_MODULE_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_LINE_ITEM_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_LINE_ITEM_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_MODULE_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_LINE_ITEM_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanLineItem.create_for_modification( + qualified_name=qualified_name, name=name + ) + + +def test_create_for_modification(): + sut = AnaplanLineItem.create_for_modification( + qualified_name=ANAPLAN_LINE_ITEM_QUALIFIED_NAME, name=ANAPLAN_LINE_ITEM_NAME + ) + + assert sut.qualified_name == ANAPLAN_LINE_ITEM_QUALIFIED_NAME + assert sut.name == ANAPLAN_LINE_ITEM_NAME + + +def test_trim_to_required(): + sut = AnaplanLineItem.create_for_modification( + name=ANAPLAN_LINE_ITEM_NAME, qualified_name=ANAPLAN_LINE_ITEM_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_LINE_ITEM_NAME + assert sut.qualified_name == ANAPLAN_LINE_ITEM_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_list_test.py b/tests/unit/model/anaplan_list_test.py new file mode 100644 index 00000000..c862fd4e --- /dev/null +++ b/tests/unit/model/anaplan_list_test.py @@ -0,0 +1,70 @@ +import pytest + +from pyatlan.model.assets import AnaplanList +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_LIST_NAME, + ANAPLAN_LIST_QUALIFIED_NAME, + ANAPLAN_MODEL_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_LIST_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanList.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanList.creator( + name=ANAPLAN_LIST_NAME, + model_qualified_name=ANAPLAN_MODEL_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_LIST_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_LIST_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_MODEL_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_LIST_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanList.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanList.create_for_modification( + qualified_name=ANAPLAN_LIST_QUALIFIED_NAME, name=ANAPLAN_LIST_NAME + ) + + assert sut.qualified_name == ANAPLAN_LIST_QUALIFIED_NAME + assert sut.name == ANAPLAN_LIST_NAME + + +def test_trim_to_required(): + sut = AnaplanList.create_for_modification( + name=ANAPLAN_LIST_NAME, qualified_name=ANAPLAN_LIST_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_LIST_NAME + assert sut.qualified_name == ANAPLAN_LIST_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_model_test.py b/tests/unit/model/anaplan_model_test.py new file mode 100644 index 00000000..b8328f84 --- /dev/null +++ b/tests/unit/model/anaplan_model_test.py @@ -0,0 +1,70 @@ +import pytest + +from pyatlan.model.assets import AnaplanModel +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_MODEL_NAME, + ANAPLAN_MODEL_QUALIFIED_NAME, + ANAPLAN_WORKSPACE_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_MODEL_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanModel.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanModel.creator( + name=ANAPLAN_MODEL_NAME, + workspace_qualified_name=ANAPLAN_WORKSPACE_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_MODEL_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_MODEL_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_WORKSPACE_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_MODEL_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanModel.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanModel.create_for_modification( + qualified_name=ANAPLAN_MODEL_QUALIFIED_NAME, name=ANAPLAN_MODEL_NAME + ) + + assert sut.qualified_name == ANAPLAN_MODEL_QUALIFIED_NAME + assert sut.name == ANAPLAN_MODEL_NAME + + +def test_trim_to_required(): + sut = AnaplanModel.create_for_modification( + name=ANAPLAN_MODEL_NAME, qualified_name=ANAPLAN_MODEL_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_MODEL_NAME + assert sut.qualified_name == ANAPLAN_MODEL_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_module_test.py b/tests/unit/model/anaplan_module_test.py new file mode 100644 index 00000000..c1bb5d8f --- /dev/null +++ b/tests/unit/model/anaplan_module_test.py @@ -0,0 +1,70 @@ +import pytest + +from pyatlan.model.assets import AnaplanModule +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_MODEL_QUALIFIED_NAME, + ANAPLAN_MODULE_NAME, + ANAPLAN_MODULE_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_MODULE_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanModule.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanModule.creator( + name=ANAPLAN_MODULE_NAME, + model_qualified_name=ANAPLAN_MODEL_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_MODULE_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_MODULE_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_MODEL_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_MODULE_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanModule.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanModule.create_for_modification( + qualified_name=ANAPLAN_MODULE_QUALIFIED_NAME, name=ANAPLAN_MODULE_NAME + ) + + assert sut.qualified_name == ANAPLAN_MODULE_QUALIFIED_NAME + assert sut.name == ANAPLAN_MODULE_NAME + + +def test_trim_to_required(): + sut = AnaplanModule.create_for_modification( + name=ANAPLAN_MODULE_NAME, qualified_name=ANAPLAN_MODULE_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_MODULE_NAME + assert sut.qualified_name == ANAPLAN_MODULE_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_page_test.py b/tests/unit/model/anaplan_page_test.py new file mode 100644 index 00000000..359369fc --- /dev/null +++ b/tests/unit/model/anaplan_page_test.py @@ -0,0 +1,70 @@ +import pytest + +from pyatlan.model.assets import AnaplanPage +from tests.unit.model.constants import ( + ANAPLAN_APP_QUALIFIED_NAME, + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_PAGE_NAME, + ANAPLAN_PAGE_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_PAGE_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanPage.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanPage.creator( + name=ANAPLAN_PAGE_NAME, + app_qualified_name=ANAPLAN_APP_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_PAGE_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_PAGE_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_APP_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_PAGE_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanPage.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanPage.create_for_modification( + qualified_name=ANAPLAN_PAGE_QUALIFIED_NAME, name=ANAPLAN_PAGE_NAME + ) + + assert sut.qualified_name == ANAPLAN_PAGE_QUALIFIED_NAME + assert sut.name == ANAPLAN_PAGE_NAME + + +def test_trim_to_required(): + sut = AnaplanPage.create_for_modification( + name=ANAPLAN_PAGE_NAME, qualified_name=ANAPLAN_PAGE_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_PAGE_NAME + assert sut.qualified_name == ANAPLAN_PAGE_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_view_test.py b/tests/unit/model/anaplan_view_test.py new file mode 100644 index 00000000..25a84311 --- /dev/null +++ b/tests/unit/model/anaplan_view_test.py @@ -0,0 +1,70 @@ +import pytest + +from pyatlan.model.assets import AnaplanView +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_MODULE_QUALIFIED_NAME, + ANAPLAN_VIEW_NAME, + ANAPLAN_VIEW_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_VIEW_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanView.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanView.creator( + name=ANAPLAN_VIEW_NAME, + module_qualified_name=ANAPLAN_MODULE_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_VIEW_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_VIEW_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_MODULE_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_VIEW_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanView.create_for_modification(qualified_name=qualified_name, name=name) + + +def test_create_for_modification(): + sut = AnaplanView.create_for_modification( + qualified_name=ANAPLAN_VIEW_QUALIFIED_NAME, name=ANAPLAN_VIEW_NAME + ) + + assert sut.qualified_name == ANAPLAN_VIEW_QUALIFIED_NAME + assert sut.name == ANAPLAN_VIEW_NAME + + +def test_trim_to_required(): + sut = AnaplanView.create_for_modification( + name=ANAPLAN_VIEW_NAME, qualified_name=ANAPLAN_VIEW_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_VIEW_NAME + assert sut.qualified_name == ANAPLAN_VIEW_QUALIFIED_NAME diff --git a/tests/unit/model/anaplan_workspace_test.py b/tests/unit/model/anaplan_workspace_test.py new file mode 100644 index 00000000..9d32de21 --- /dev/null +++ b/tests/unit/model/anaplan_workspace_test.py @@ -0,0 +1,71 @@ +import pytest + +from pyatlan.model.assets import AnaplanWorkspace +from tests.unit.model.constants import ( + ANAPLAN_CONNECTION_QUALIFIED_NAME, + ANAPLAN_CONNECTOR_TYPE, + ANAPLAN_WORKSPACE_NAME, + ANAPLAN_WORKSPACE_QUALIFIED_NAME, +) + + +@pytest.mark.parametrize( + "name, connection_qualified_name, message", + [ + (None, "connection/name", "name is required"), + (ANAPLAN_WORKSPACE_NAME, None, "connection_qualified_name is required"), + ], +) +def test_create_with_missing_parameters_raise_value_error( + name: str, connection_qualified_name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanWorkspace.create( + name=name, connection_qualified_name=connection_qualified_name + ) + + +def test_create(): + sut = AnaplanWorkspace.creator( + name=ANAPLAN_WORKSPACE_NAME, + connection_qualified_name=ANAPLAN_CONNECTION_QUALIFIED_NAME, + ) + + assert sut.name == ANAPLAN_WORKSPACE_NAME + assert sut.connection_qualified_name == ANAPLAN_CONNECTION_QUALIFIED_NAME + assert sut.qualified_name == ANAPLAN_WORKSPACE_QUALIFIED_NAME + assert sut.connector_name == ANAPLAN_CONNECTOR_TYPE + + +@pytest.mark.parametrize( + "qualified_name, name, message", + [ + (None, ANAPLAN_CONNECTION_QUALIFIED_NAME, "qualified_name is required"), + (ANAPLAN_WORKSPACE_NAME, None, "name is required"), + ], +) +def test_create_for_modification_with_invalid_parameter_raises_value_error( + qualified_name: str, name: str, message: str +): + with pytest.raises(ValueError, match=message): + AnaplanWorkspace.create_for_modification( + qualified_name=qualified_name, name=name + ) + + +def test_create_for_modification(): + sut = AnaplanWorkspace.create_for_modification( + qualified_name=ANAPLAN_WORKSPACE_QUALIFIED_NAME, name=ANAPLAN_WORKSPACE_NAME + ) + + assert sut.qualified_name == ANAPLAN_WORKSPACE_QUALIFIED_NAME + assert sut.name == ANAPLAN_WORKSPACE_NAME + + +def test_trim_to_required(): + sut = AnaplanWorkspace.create_for_modification( + name=ANAPLAN_WORKSPACE_NAME, qualified_name=ANAPLAN_WORKSPACE_QUALIFIED_NAME + ).trim_to_required() + + assert sut.name == ANAPLAN_WORKSPACE_NAME + assert sut.qualified_name == ANAPLAN_WORKSPACE_QUALIFIED_NAME diff --git a/tests/unit/model/constants.py b/tests/unit/model/constants.py index f2c9cdad..93fed9ae 100644 --- a/tests/unit/model/constants.py +++ b/tests/unit/model/constants.py @@ -44,6 +44,34 @@ ADLS_CONTAINER_QUALIFIED_NAME = f"{ADLS_QUALIFIED_NAME}/{ADLS_CONTAINER_NAME}" # "default/adls/123456789/myaccount/mycontainer/myobject.csv" ADLS_OBJECT_QUALIFIED_NAME = f"{ADLS_CONTAINER_QUALIFIED_NAME}/{ADLS_OBJECT_NAME}" +ANAPLAN_CONNECTION_QUALIFIED_NAME = "default/anaplan/123456789" +ANAPLAN_CONNECTOR_TYPE = "anaplan" +ANAPLAN_WORKSPACE_NAME = "anaplan-workspace" +ANAPLAN_WORKSPACE_QUALIFIED_NAME = ( + f"{ANAPLAN_CONNECTION_QUALIFIED_NAME}/{ANAPLAN_WORKSPACE_NAME}" +) +ANAPLAN_APP_NAME = "anaplan-app" +ANAPLAN_APP_QUALIFIED_NAME = f"{ANAPLAN_CONNECTION_QUALIFIED_NAME}/{ANAPLAN_APP_NAME}" +ANAPLAN_PAGE_NAME = "anaplan-page" +ANAPLAN_PAGE_QUALIFIED_NAME = f"{ANAPLAN_APP_QUALIFIED_NAME}/{ANAPLAN_PAGE_NAME}" +ANAPLAN_MODEL_NAME = "anaplan-model" +ANAPLAN_MODEL_QUALIFIED_NAME = ( + f"{ANAPLAN_WORKSPACE_QUALIFIED_NAME}/{ANAPLAN_MODEL_NAME}" +) +ANAPLAN_MODULE_NAME = "anaplan-module" +ANAPLAN_MODULE_QUALIFIED_NAME = f"{ANAPLAN_MODEL_QUALIFIED_NAME}/{ANAPLAN_MODULE_NAME}" +ANAPLAN_LIST_NAME = "anaplan-list" +ANAPLAN_LIST_QUALIFIED_NAME = f"{ANAPLAN_MODEL_QUALIFIED_NAME}/{ANAPLAN_LIST_NAME}" +ANAPLAN_DIMENSION_NAME = "anaplan-list" +ANAPLAN_DIMENSION_QUALIFIED_NAME = ( + f"{ANAPLAN_MODEL_QUALIFIED_NAME}/{ANAPLAN_DIMENSION_NAME}" +) +ANAPLAN_LINE_ITEM_NAME = "anaplan-lineitem" +ANAPLAN_LINE_ITEM_QUALIFIED_NAME = ( + f"{ANAPLAN_MODULE_QUALIFIED_NAME}/{ANAPLAN_LINE_ITEM_NAME}" +) +ANAPLAN_VIEW_NAME = "anaplan-view" +ANAPLAN_VIEW_QUALIFIED_NAME = f"{ANAPLAN_MODULE_QUALIFIED_NAME}/{ANAPLAN_VIEW_NAME}" API_SPEC_NAME = "api-spec" API_PATH_NAME = "/api/path" API_OBJECT_NAME = "api-object" diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index b523dc0f..c296d29b 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -22,6 +22,15 @@ ADLSObject, AirflowDag, AirflowTask, + AnaplanApp, + AnaplanDimension, + AnaplanLineItem, + AnaplanList, + AnaplanModel, + AnaplanModule, + AnaplanPage, + AnaplanView, + AnaplanWorkspace, APIField, APIObject, APIPath, @@ -321,6 +330,15 @@ "Optional[ADLSAccount]": ADLSAccount(), "Optional[List[ADLSObject]]": [ADLSObject()], "Optional[ADLSContainer]": ADLSContainer(), + "Optional[AnaplanWorkspace]": AnaplanWorkspace(), + "Optional[List[AnaplanApp]]": [AnaplanApp()], + "Optional[List[AnaplanPage]]": [AnaplanPage()], + "Optional[List[AnaplanModel]]": [AnaplanModel()], + "Optional[List[AnaplanModule]]": [AnaplanModule()], + "Optional[List[AnaplanLineItem]]": [AnaplanLineItem()], + "Optional[List[AnaplanView]]": [AnaplanView()], + "Optional[List[AnaplanList]]": [AnaplanList()], + "Optional[List[AnaplanDimension]]": [AnaplanDimension()], "Optional[List[S3Object]]": [S3Object()], "Optional[S3Bucket]": S3Bucket(), "Optional[List[Asset]]": [Asset()], From 22f3e6905ea1cfa1e7dcf8599eae43dcc482afe9 Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 20:04:37 +0530 Subject: [PATCH 14/66] unit test - fix --- tests/unit/model/anaplan_dimension_test.py | 10 +++++----- tests/unit/model/anaplan_line_item_test.py | 10 +++++----- tests/unit/model/anaplan_list_test.py | 10 +++++----- tests/unit/model/anaplan_model_test.py | 10 +++++----- tests/unit/model/anaplan_module_test.py | 10 +++++----- tests/unit/model/anaplan_page_test.py | 10 +++++----- tests/unit/model/anaplan_view_test.py | 10 +++++----- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/unit/model/anaplan_dimension_test.py b/tests/unit/model/anaplan_dimension_test.py index 94ed061b..bc51c121 100644 --- a/tests/unit/model/anaplan_dimension_test.py +++ b/tests/unit/model/anaplan_dimension_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, model_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_DIMENSION_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_DIMENSION_NAME, None, "model_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanDimension.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanDimension.creator( + name=name, model_qualified_name=model_qualified_name ) diff --git a/tests/unit/model/anaplan_line_item_test.py b/tests/unit/model/anaplan_line_item_test.py index 2a145b5f..cf5d731f 100644 --- a/tests/unit/model/anaplan_line_item_test.py +++ b/tests/unit/model/anaplan_line_item_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, module_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_LINE_ITEM_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_LINE_ITEM_NAME, None, "module_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, module_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanLineItem.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanLineItem.creator( + name=name, connection_qualified_name=module_qualified_name ) diff --git a/tests/unit/model/anaplan_list_test.py b/tests/unit/model/anaplan_list_test.py index c862fd4e..5b7b65b5 100644 --- a/tests/unit/model/anaplan_list_test.py +++ b/tests/unit/model/anaplan_list_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, model_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_LIST_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_LIST_NAME, None, "model_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanList.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanList.creator( + name=name, connection_qualified_name=model_qualified_name ) diff --git a/tests/unit/model/anaplan_model_test.py b/tests/unit/model/anaplan_model_test.py index b8328f84..e12197e8 100644 --- a/tests/unit/model/anaplan_model_test.py +++ b/tests/unit/model/anaplan_model_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, workspace_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_MODEL_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_MODEL_NAME, None, "workspace_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, workspace_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanModel.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanModel.creator( + name=name, workspace_qualified_name=workspace_qualified_name ) diff --git a/tests/unit/model/anaplan_module_test.py b/tests/unit/model/anaplan_module_test.py index c1bb5d8f..62102680 100644 --- a/tests/unit/model/anaplan_module_test.py +++ b/tests/unit/model/anaplan_module_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, model_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_MODULE_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_MODULE_NAME, None, "model_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanModule.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanModule.creator( + name=name, model_qualified_name=model_qualified_name ) diff --git a/tests/unit/model/anaplan_page_test.py b/tests/unit/model/anaplan_page_test.py index 359369fc..53a8ae69 100644 --- a/tests/unit/model/anaplan_page_test.py +++ b/tests/unit/model/anaplan_page_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, app_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_PAGE_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_PAGE_NAME, None, "app_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, app_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanPage.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanPage.creator( + name=name, app_qualified_name=app_qualified_name ) diff --git a/tests/unit/model/anaplan_view_test.py b/tests/unit/model/anaplan_view_test.py index 25a84311..889542a5 100644 --- a/tests/unit/model/anaplan_view_test.py +++ b/tests/unit/model/anaplan_view_test.py @@ -11,18 +11,18 @@ @pytest.mark.parametrize( - "name, connection_qualified_name, message", + "name, module_qualified_name, message", [ (None, "connection/name", "name is required"), - (ANAPLAN_VIEW_NAME, None, "connection_qualified_name is required"), + (ANAPLAN_VIEW_NAME, None, "module_qualified_name is required"), ], ) def test_create_with_missing_parameters_raise_value_error( - name: str, connection_qualified_name: str, message: str + name: str, module_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanView.create( - name=name, connection_qualified_name=connection_qualified_name + AnaplanView.creator( + name=name, module_qualified_name=module_qualified_name ) From 25b4ccbcd9f9850b3cf1ba714af88336d823593f Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 20:08:28 +0530 Subject: [PATCH 15/66] unit test - fix --- tests/unit/model/anaplan_line_item_test.py | 2 +- tests/unit/model/anaplan_list_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/model/anaplan_line_item_test.py b/tests/unit/model/anaplan_line_item_test.py index cf5d731f..0a66e0e5 100644 --- a/tests/unit/model/anaplan_line_item_test.py +++ b/tests/unit/model/anaplan_line_item_test.py @@ -22,7 +22,7 @@ def test_create_with_missing_parameters_raise_value_error( ): with pytest.raises(ValueError, match=message): AnaplanLineItem.creator( - name=name, connection_qualified_name=module_qualified_name + name=name, module_qualified_name=module_qualified_name ) diff --git a/tests/unit/model/anaplan_list_test.py b/tests/unit/model/anaplan_list_test.py index 5b7b65b5..490b3d11 100644 --- a/tests/unit/model/anaplan_list_test.py +++ b/tests/unit/model/anaplan_list_test.py @@ -22,7 +22,7 @@ def test_create_with_missing_parameters_raise_value_error( ): with pytest.raises(ValueError, match=message): AnaplanList.creator( - name=name, connection_qualified_name=model_qualified_name + name=name, model_qualified_name=model_qualified_name ) From e1b22bd675f99ff97f24ba11ad3bd5771a9126d7 Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Fri, 27 Dec 2024 20:13:19 +0530 Subject: [PATCH 16/66] blake8 - fix --- tests/unit/model/anaplan_dimension_test.py | 4 +--- tests/unit/model/anaplan_line_item_test.py | 4 +--- tests/unit/model/anaplan_list_test.py | 4 +--- tests/unit/model/anaplan_module_test.py | 4 +--- tests/unit/model/anaplan_page_test.py | 4 +--- tests/unit/model/anaplan_view_test.py | 4 +--- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/tests/unit/model/anaplan_dimension_test.py b/tests/unit/model/anaplan_dimension_test.py index bc51c121..241577af 100644 --- a/tests/unit/model/anaplan_dimension_test.py +++ b/tests/unit/model/anaplan_dimension_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanDimension.creator( - name=name, model_qualified_name=model_qualified_name - ) + AnaplanDimension.creator(name=name, model_qualified_name=model_qualified_name) def test_create(): diff --git a/tests/unit/model/anaplan_line_item_test.py b/tests/unit/model/anaplan_line_item_test.py index 0a66e0e5..06694a6b 100644 --- a/tests/unit/model/anaplan_line_item_test.py +++ b/tests/unit/model/anaplan_line_item_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, module_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanLineItem.creator( - name=name, module_qualified_name=module_qualified_name - ) + AnaplanLineItem.creator(name=name, module_qualified_name=module_qualified_name) def test_create(): diff --git a/tests/unit/model/anaplan_list_test.py b/tests/unit/model/anaplan_list_test.py index 490b3d11..c43e50d5 100644 --- a/tests/unit/model/anaplan_list_test.py +++ b/tests/unit/model/anaplan_list_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanList.creator( - name=name, model_qualified_name=model_qualified_name - ) + AnaplanList.creator(name=name, model_qualified_name=model_qualified_name) def test_create(): diff --git a/tests/unit/model/anaplan_module_test.py b/tests/unit/model/anaplan_module_test.py index 62102680..62808364 100644 --- a/tests/unit/model/anaplan_module_test.py +++ b/tests/unit/model/anaplan_module_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, model_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanModule.creator( - name=name, model_qualified_name=model_qualified_name - ) + AnaplanModule.creator(name=name, model_qualified_name=model_qualified_name) def test_create(): diff --git a/tests/unit/model/anaplan_page_test.py b/tests/unit/model/anaplan_page_test.py index 53a8ae69..1bbf766c 100644 --- a/tests/unit/model/anaplan_page_test.py +++ b/tests/unit/model/anaplan_page_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, app_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanPage.creator( - name=name, app_qualified_name=app_qualified_name - ) + AnaplanPage.creator(name=name, app_qualified_name=app_qualified_name) def test_create(): diff --git a/tests/unit/model/anaplan_view_test.py b/tests/unit/model/anaplan_view_test.py index 889542a5..3250a5a0 100644 --- a/tests/unit/model/anaplan_view_test.py +++ b/tests/unit/model/anaplan_view_test.py @@ -21,9 +21,7 @@ def test_create_with_missing_parameters_raise_value_error( name: str, module_qualified_name: str, message: str ): with pytest.raises(ValueError, match=message): - AnaplanView.creator( - name=name, module_qualified_name=module_qualified_name - ) + AnaplanView.creator(name=name, module_qualified_name=module_qualified_name) def test_create(): From e52264368a0a94ae9fded2d6a4891cd18f93d21f Mon Sep 17 00:00:00 2001 From: prateekrai-atlan Date: Sat, 28 Dec 2024 16:23:08 +0530 Subject: [PATCH 17/66] Create anaplan_asset_test.py --- tests/integration/anaplan_asset_test.py | 686 ++++++++++++++++++++++++ 1 file changed, 686 insertions(+) create mode 100644 tests/integration/anaplan_asset_test.py diff --git a/tests/integration/anaplan_asset_test.py b/tests/integration/anaplan_asset_test.py new file mode 100644 index 00000000..7a61044f --- /dev/null +++ b/tests/integration/anaplan_asset_test.py @@ -0,0 +1,686 @@ +from typing import Generator + +import pytest + +from pyatlan.client.atlan import AtlanClient +from pyatlan.model.assets import ( + AnaplanApp, + AnaplanDimension, + AnaplanLineItem, + AnaplanList, + AnaplanModel, + AnaplanModule, + AnaplanPage, + AnaplanView, + AnaplanWorkspace, + Connection, +) +from pyatlan.model.core import Announcement +from pyatlan.model.enums import ( + AnnouncementType, + AtlanConnectorType, + CertificateStatus, + EntityStatus, +) +from pyatlan.model.response import AssetMutationResponse +from tests.integration.client import TestId, delete_asset +from tests.integration.connection_test import create_connection +from tests.integration.utils import block + +MODULE_NAME = TestId.make_unique("ANAPLAN") + +CONNECTOR_TYPE = AtlanConnectorType.ANAPLAN +ANAPLAN_WORKSPACE_NAME = f"{MODULE_NAME}-anaplan-workspace" +ANAPLAN_APP_NAME = f"{MODULE_NAME}-anaplan-app" +ANAPLAN_PAGE_NAME = f"{MODULE_NAME}-anaplan-page" +ANAPLAN_PAGE_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-page-overload" +ANAPLAN_MODEL_NAME = f"{MODULE_NAME}-anaplan-model" +ANAPLAN_MODEL_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-model-overload" +ANAPLAN_MODULE_NAME = f"{MODULE_NAME}-anaplan-module" +ANAPLAN_MODULE_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-module-overload" +ANAPLAN_LIST_NAME = f"{MODULE_NAME}-anaplan-list" +ANAPLAN_LIST_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-list-overload" +ANAPLAN_DIMENSION_NAME = f"{MODULE_NAME}-anaplan-dimension" +ANAPLAN_DIMENSION_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-dimension-overload" +ANAPLAN_LINEITEM_NAME = f"{MODULE_NAME}-anaplan-lineitem" +ANAPLAN_LINEITEM_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-lineitem-overload" +ANAPLAN_VIEW_NAME = f"{MODULE_NAME}-anaplan-view" +ANAPLAN_VIEW_NAME_OVERLOAD = f"{MODULE_NAME}-anaplan-view-overload" + +CERTIFICATE_STATUS = CertificateStatus.VERIFIED +CERTIFICATE_MESSAGE = "Automated testing of the Python SDK." +ANNOUNCEMENT_TYPE = AnnouncementType.INFORMATION +ANNOUNCEMENT_TITLE = "Python SDK testing." +ANNOUNCEMENT_MESSAGE = "Automated testing of the Python SDK." + + +response = block(AtlanClient(), AssetMutationResponse()) + + +@pytest.fixture(scope="module") +def connection(client: AtlanClient) -> Generator[Connection, None, None]: + result = create_connection( + client=client, name=MODULE_NAME, connector_type=CONNECTOR_TYPE + ) + yield result + delete_asset(client, guid=result.guid, asset_type=Connection) + + +@pytest.fixture(scope="module") +def anaplan_workspace( + client: AtlanClient, connection: Connection +) -> Generator[AnaplanWorkspace, None, None]: + assert connection.qualified_name + to_create = AnaplanWorkspace.creator( + name=ANAPLAN_WORKSPACE_NAME, connection_qualified_name=connection.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanWorkspace)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanWorkspace) + + +def test_anaplan_workspace( + client: AtlanClient, connection: Connection, anaplan_workspace: AnaplanWorkspace +): + assert anaplan_workspace + assert anaplan_workspace.guid + assert anaplan_workspace.qualified_name + assert anaplan_workspace.name == ANAPLAN_WORKSPACE_NAME + assert anaplan_workspace.connection_qualified_name == connection.qualified_name + assert anaplan_workspace.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_app( + client: AtlanClient, connection: Connection +) -> Generator[AnaplanApp, None, None]: + assert connection.qualified_name + to_create = AnaplanApp.creator( + name=ANAPLAN_APP_NAME, connection_qualified_name=connection.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanApp)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanApp) + + +def test_anaplan_app( + client: AtlanClient, connection: Connection, anaplan_app: AnaplanApp +): + assert anaplan_app + assert anaplan_app.guid + assert anaplan_app.qualified_name + assert anaplan_app.name == ANAPLAN_APP_NAME + assert anaplan_app.connection_qualified_name == connection.qualified_name + assert anaplan_app.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_page( + client: AtlanClient, app: AnaplanApp +) -> Generator[AnaplanPage, None, None]: + assert app.qualified_name + to_create = AnaplanPage.creator( + name=ANAPLAN_PAGE_NAME, app_qualified_name=app.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanPage)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanPage) + + +def test_anaplan_page( + client: AtlanClient, anaplan_app: AnaplanApp, anaplan_page: AnaplanPage +): + assert anaplan_page + assert anaplan_page.guid + assert anaplan_page.qualified_name + assert anaplan_page.name == ANAPLAN_PAGE_NAME + assert ( + anaplan_page.connection_qualified_name == anaplan_app.connection_qualified_name + ) + assert anaplan_page.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_page_overload( + client: AtlanClient, connection: Connection, app: AnaplanApp +) -> Generator[AnaplanPage, None, None]: + assert connection.qualified_name + assert app.qualified_name + to_create = AnaplanPage.creator( + name=ANAPLAN_PAGE_NAME_OVERLOAD, + app_qualified_name=app.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanPage)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanPage) + + +def test_overload_anaplan_page( + client: AtlanClient, anaplan_app: AnaplanApp, anaplan_page_overload: AnaplanPage +): + assert anaplan_page_overload + assert anaplan_page_overload.guid + assert anaplan_page_overload.qualified_name + assert anaplan_page_overload.name == ANAPLAN_PAGE_NAME_OVERLOAD + assert ( + anaplan_page_overload.connection_qualified_name + == anaplan_app.connection_qualified_name + ) + assert anaplan_page_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_model( + client: AtlanClient, workspace: AnaplanWorkspace +) -> Generator[AnaplanModel, None, None]: + assert workspace.qualified_name + to_create = AnaplanModel.creator( + name=ANAPLAN_MODEL_NAME, workspace_qualified_name=workspace.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanModel)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanModel) + + +def test_anaplan_model( + client: AtlanClient, + anaplan_workspace: AnaplanWorkspace, + anaplan_model: AnaplanModel, +): + assert anaplan_model + assert anaplan_model.guid + assert anaplan_model.qualified_name + assert anaplan_model.name == ANAPLAN_MODEL_NAME + assert ( + anaplan_model.connection_qualified_name + == anaplan_workspace.connection_qualified_name + ) + assert anaplan_model.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_model_overload( + client: AtlanClient, connection: Connection, workspace: AnaplanWorkspace +) -> Generator[AnaplanModel, None, None]: + assert connection.qualified_name + assert workspace.qualified_name + to_create = AnaplanModel.creator( + name=ANAPLAN_MODEL_NAME_OVERLOAD, + workspace_qualified_name=workspace.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanModel)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanModel) + + +def test_overload_anaplan_model( + client: AtlanClient, + anaplan_workspace: AnaplanWorkspace, + anaplan_model_overload: AnaplanModel, +): + assert anaplan_model_overload + assert anaplan_model_overload.guid + assert anaplan_model_overload.qualified_name + assert anaplan_model_overload.name == ANAPLAN_MODEL_NAME_OVERLOAD + assert ( + anaplan_model_overload.connection_qualified_name + == anaplan_workspace.connection_qualified_name + ) + assert anaplan_model_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_module( + client: AtlanClient, model: AnaplanModel +) -> Generator[AnaplanModule, None, None]: + assert model.qualified_name + to_create = AnaplanModule.creator( + name=ANAPLAN_MODULE_NAME, model_qualified_name=model.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanModule)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanModule) + + +def test_anaplan_module( + client: AtlanClient, anaplan_model: AnaplanModel, anaplan_module: AnaplanModule +): + assert anaplan_module + assert anaplan_module.guid + assert anaplan_module.qualified_name + assert anaplan_module.name == ANAPLAN_MODULE_NAME + assert ( + anaplan_module.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_module.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_module_overload( + client: AtlanClient, connection: Connection, model: AnaplanModel +) -> Generator[AnaplanModule, None, None]: + assert connection.qualified_name + assert model.qualified_name + to_create = AnaplanModule.creator( + name=ANAPLAN_MODULE_NAME_OVERLOAD, + model_qualified_name=model.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanModule)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanModule) + + +def test_overload_anaplan_module( + client: AtlanClient, + anaplan_model: AnaplanModel, + anaplan_module_overload: AnaplanModule, +): + assert anaplan_module_overload + assert anaplan_module_overload.guid + assert anaplan_module_overload.qualified_name + assert anaplan_module_overload.name == ANAPLAN_MODULE_NAME_OVERLOAD + assert ( + anaplan_module_overload.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_module_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_list( + client: AtlanClient, model: AnaplanModel +) -> Generator[AnaplanList, None, None]: + assert model.qualified_name + to_create = AnaplanList.creator( + name=ANAPLAN_LIST_NAME, model_qualified_name=model.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanList)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanList) + + +def test_anaplan_list( + client: AtlanClient, anaplan_model: AnaplanModel, anaplan_list: AnaplanList +): + assert anaplan_list + assert anaplan_list.guid + assert anaplan_list.qualified_name + assert anaplan_list.name == ANAPLAN_LIST_NAME + assert ( + anaplan_list.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_list.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_list_overload( + client: AtlanClient, connection: Connection, model: AnaplanModel +) -> Generator[AnaplanList, None, None]: + assert connection.qualified_name + assert model.qualified_name + to_create = AnaplanList.creator( + name=ANAPLAN_LIST_NAME_OVERLOAD, + model_qualified_name=model.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanList)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanList) + + +def test_overload_anaplan_list( + client: AtlanClient, anaplan_model: AnaplanModel, anaplan_list_overload: AnaplanList +): + assert anaplan_list_overload + assert anaplan_list_overload.guid + assert anaplan_list_overload.qualified_name + assert anaplan_list_overload.name == ANAPLAN_LIST_NAME_OVERLOAD + assert ( + anaplan_list_overload.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_list_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_dimension( + client: AtlanClient, model: AnaplanModel +) -> Generator[AnaplanDimension, None, None]: + assert model.qualified_name + to_create = AnaplanDimension.creator( + name=ANAPLAN_DIMENSION_NAME, model_qualified_name=model.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanDimension)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanDimension) + + +def test_anaplan_dimension( + client: AtlanClient, + anaplan_model: AnaplanModel, + anaplan_dimension: AnaplanDimension, +): + assert anaplan_dimension + assert anaplan_dimension.guid + assert anaplan_dimension.qualified_name + assert anaplan_dimension.name == ANAPLAN_DIMENSION_NAME + assert ( + anaplan_dimension.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_dimension.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_dimension_overload( + client: AtlanClient, connection: Connection, model: AnaplanModel +) -> Generator[AnaplanDimension, None, None]: + assert connection.qualified_name + assert model.qualified_name + to_create = AnaplanDimension.creator( + name=ANAPLAN_DIMENSION_NAME_OVERLOAD, + model_qualified_name=model.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanDimension)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanDimension) + + +def test_overload_anaplan_dimension( + client: AtlanClient, + anaplan_model: AnaplanModel, + anaplan_dimension_overload: AnaplanDimension, +): + assert anaplan_dimension_overload + assert anaplan_dimension_overload.guid + assert anaplan_dimension_overload.qualified_name + assert anaplan_dimension_overload.name == ANAPLAN_DIMENSION_NAME_OVERLOAD + assert ( + anaplan_dimension_overload.connection_qualified_name + == anaplan_model.connection_qualified_name + ) + assert anaplan_dimension_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_lineitem( + client: AtlanClient, module: AnaplanModule +) -> Generator[AnaplanLineItem, None, None]: + assert module.qualified_name + to_create = AnaplanLineItem.creator( + name=ANAPLAN_LINEITEM_NAME, module_qualified_name=module.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanLineItem)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanLineItem) + + +def test_anaplan_lineitem( + client: AtlanClient, + anaplan_module: AnaplanModule, + anaplan_lineitem: AnaplanLineItem, +): + assert anaplan_lineitem + assert anaplan_lineitem.guid + assert anaplan_lineitem.qualified_name + assert anaplan_lineitem.name == ANAPLAN_LINEITEM_NAME + assert ( + anaplan_lineitem.connection_qualified_name + == anaplan_module.connection_qualified_name + ) + assert anaplan_lineitem.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_lineitem_overload( + client: AtlanClient, connection: Connection, module: AnaplanModule +) -> Generator[AnaplanLineItem, None, None]: + assert connection.qualified_name + assert module.qualified_name + to_create = AnaplanLineItem.creator( + name=ANAPLAN_LINEITEM_NAME_OVERLOAD, + module_qualified_name=module.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanLineItem)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanLineItem) + + +def test_overload_anaplan_lineitem( + client: AtlanClient, + anaplan_module: AnaplanModule, + anaplan_lineitem_overload: AnaplanLineItem, +): + assert anaplan_lineitem_overload + assert anaplan_lineitem_overload.guid + assert anaplan_lineitem_overload.qualified_name + assert anaplan_lineitem_overload.name == ANAPLAN_LINEITEM_NAME_OVERLOAD + assert ( + anaplan_lineitem_overload.connection_qualified_name + == anaplan_module.connection_qualified_name + ) + assert anaplan_lineitem_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_view( + client: AtlanClient, module: AnaplanModule +) -> Generator[AnaplanView, None, None]: + assert module.qualified_name + to_create = AnaplanView.creator( + name=ANAPLAN_VIEW_NAME, module_qualified_name=module.qualified_name + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanView)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanView) + + +def test_anaplan_view( + client: AtlanClient, anaplan_module: AnaplanModule, anaplan_view: AnaplanView +): + assert anaplan_view + assert anaplan_view.guid + assert anaplan_view.qualified_name + assert anaplan_view.name == ANAPLAN_VIEW_NAME + assert ( + anaplan_view.connection_qualified_name + == anaplan_module.connection_qualified_name + ) + assert anaplan_view.connector_name == AtlanConnectorType.ANAPLAN.value + + +@pytest.fixture(scope="module") +def anaplan_view_overload( + client: AtlanClient, connection: Connection, module: AnaplanModule +) -> Generator[AnaplanView, None, None]: + assert connection.qualified_name + assert module.qualified_name + to_create = AnaplanView.creator( + name=ANAPLAN_VIEW_NAME_OVERLOAD, + module_qualified_name=module.qualified_name, + connection_qualified_name=connection.qualified_name, + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=AnaplanView)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=AnaplanView) + + +def test_overload_anaplan_view( + client: AtlanClient, + anaplan_module: AnaplanModule, + anaplan_view_overload: AnaplanView, +): + assert anaplan_view_overload + assert anaplan_view_overload.guid + assert anaplan_view_overload.qualified_name + assert anaplan_view_overload.name == ANAPLAN_VIEW_NAME_OVERLOAD + assert ( + anaplan_view_overload.connection_qualified_name + == anaplan_module.connection_qualified_name + ) + assert anaplan_view_overload.connector_name == AtlanConnectorType.ANAPLAN.value + + +# here +def test_update_anaplan_view( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + assert anaplan_view.qualified_name + assert anaplan_view.name + updated = client.asset.update_certificate( + asset_type=AnaplanView, + qualified_name=anaplan_view.qualified_name, + name=anaplan_view.name, + certificate_status=CERTIFICATE_STATUS, + message=CERTIFICATE_MESSAGE, + ) + assert updated + assert updated.certificate_status_message == CERTIFICATE_MESSAGE + assert anaplan_view.qualified_name + assert anaplan_view.name + updated = client.asset.update_announcement( + asset_type=AnaplanView, + qualified_name=anaplan_view.qualified_name, + name=anaplan_view.name, + announcement=Announcement( + announcement_type=ANNOUNCEMENT_TYPE, + announcement_title=ANNOUNCEMENT_TITLE, + announcement_message=ANNOUNCEMENT_MESSAGE, + ), + ) + assert updated + assert updated.announcement_type == ANNOUNCEMENT_TYPE.value + assert updated.announcement_title == ANNOUNCEMENT_TITLE + assert updated.announcement_message == ANNOUNCEMENT_MESSAGE + + +@pytest.mark.order(after="test_update_anaplan_view") +def test_retrieve_anaplan_view( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + b = client.asset.get_by_guid(anaplan_view.guid, asset_type=AnaplanView) + assert b + assert not b.is_incomplete + assert b.guid == anaplan_view.guid + assert b.qualified_name == anaplan_view.qualified_name + assert b.name == anaplan_view.name + assert b.connector_name == anaplan_view.connector_name + assert b.connection_qualified_name == anaplan_view.connection_qualified_name + assert b.certificate_status == CERTIFICATE_STATUS + assert b.certificate_status_message == CERTIFICATE_MESSAGE + + +@pytest.mark.order(after="test_retrieve_anaplan_view") +def test_update_anaplan_view_again( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + assert anaplan_view.qualified_name + assert anaplan_view.name + updated = client.asset.remove_certificate( + asset_type=AnaplanView, + qualified_name=anaplan_view.qualified_name, + name=anaplan_view.name, + ) + assert updated + assert not updated.certificate_status + assert not updated.certificate_status_message + assert updated.announcement_type == ANNOUNCEMENT_TYPE.value + assert updated.announcement_title == ANNOUNCEMENT_TITLE + assert updated.announcement_message == ANNOUNCEMENT_MESSAGE + assert anaplan_view.qualified_name + updated = client.asset.remove_announcement( + asset_type=AnaplanView, + qualified_name=anaplan_view.qualified_name, + name=anaplan_view.name, + ) + assert updated + assert not updated.announcement_type + assert not updated.announcement_title + assert not updated.announcement_message + + +@pytest.mark.order(after="test_update_anaplan_view_again") +def test_delete_anaplan_view( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + response = client.asset.delete_by_guid(anaplan_view.guid) + assert response + assert not response.assets_created(asset_type=AnaplanView) + assert not response.assets_updated(asset_type=AnaplanView) + deleted = response.assets_deleted(asset_type=AnaplanView) + assert deleted + assert len(deleted) == 1 + assert deleted[0].guid == anaplan_view.guid + assert deleted[0].qualified_name == anaplan_view.qualified_name + assert deleted[0].delete_handler == "SOFT" + assert deleted[0].status == EntityStatus.DELETED + + +@pytest.mark.order(after="test_delete_anaplan_view") +def test_read_deleted_anaplan_view( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + deleted = client.asset.get_by_guid(anaplan_view.guid, asset_type=AnaplanView) + assert deleted + assert deleted.guid == anaplan_view.guid + assert deleted.qualified_name == anaplan_view.qualified_name + assert deleted.status == EntityStatus.DELETED + + +@pytest.mark.order(after="test_read_deleted_anaplan_view") +def test_restore_anaplan_view( + client: AtlanClient, + connection: Connection, + anaplan_module: AnaplanModule, + anaplan_view: AnaplanView, +): + assert anaplan_view.qualified_name + assert client.asset.restore( + asset_type=AnaplanView, qualified_name=anaplan_view.qualified_name + ) + assert anaplan_view.qualified_name + restored = client.asset.get_by_qualified_name( + asset_type=AnaplanView, qualified_name=anaplan_view.qualified_name + ) + assert restored + assert restored.guid == anaplan_view.guid + assert restored.qualified_name == anaplan_view.qualified_name + assert restored.status == EntityStatus.ACTIVE From 3087bf4ca27150a7ca22f308f65dadc3c0046633 Mon Sep 17 00:00:00 2001 From: Rupesh Date: Mon, 30 Dec 2024 13:51:26 +0530 Subject: [PATCH 18/66] added new four aws connectors --- pyatlan/model/enums.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyatlan/model/enums.py b/pyatlan/model/enums.py index 37367490..073e8e63 100644 --- a/pyatlan/model/enums.py +++ b/pyatlan/model/enums.py @@ -337,7 +337,10 @@ def get_connector_name( IBM_DB2 = ("ibmdb2", AtlanConnectionCategory.DATABASE) APP = ("app", AtlanConnectionCategory.APP) BIGID = ("bigid", AtlanConnectionCategory.SAAS) - ANAPLAN = ("anaplan", AtlanConnectionCategory.BI) + AWS_BATCH = ("aws-batch", AtlanConnectionCategory.ELT) + AWS_ECS = ("aws-ecs", AtlanConnectionCategory.ELT) + AWS_LAMBDA = ("aws-lambda", AtlanConnectionCategory.ELT) + AWS_SAGEMAKER = ("aws-sagemaker", AtlanConnectionCategory.ELT) class AtlanCustomAttributePrimitiveType(str, Enum): From 6c6c91d3a73f135418c9ab87384b192ed6550a67 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 30 Dec 2024 18:30:22 +0530 Subject: [PATCH 19/66] FT-609: Added `creator()` for Insights objects (`Collection`, `Folder`, `Query`) --- pyatlan/errors.py | 7 ++ .../templates/methods/asset/collection.jinja2 | 23 ++++++ .../templates/methods/asset/folder.jinja2 | 39 ++++++++++ .../templates/methods/asset/query.jinja2 | 39 ++++++++++ .../methods/attribute/collection.jinja2 | 14 ++++ .../templates/methods/attribute/folder.jinja2 | 33 ++++++++ .../templates/methods/attribute/query.jinja2 | 33 ++++++++ pyatlan/model/assets/collection.py | 41 ++++++++++ pyatlan/model/assets/core/folder.py | 75 ++++++++++++++++++- pyatlan/model/assets/core/query.py | 75 ++++++++++++++++++- 10 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 pyatlan/generator/templates/methods/asset/collection.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/folder.jinja2 create mode 100644 pyatlan/generator/templates/methods/asset/query.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/collection.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/folder.jinja2 create mode 100644 pyatlan/generator/templates/methods/attribute/query.jinja2 diff --git a/pyatlan/errors.py b/pyatlan/errors.py index 994b2d8b..4d0465b6 100644 --- a/pyatlan/errors.py +++ b/pyatlan/errors.py @@ -608,6 +608,13 @@ class ErrorCode(Enum): "Ensure the provided username is correct and valid.", InvalidRequestError, ) + UNABLE_TO_GENERATE_QN = ( + 400, + "ATLAN-PYTHON-400-070", + "Unable to generate qualifiedName for {0}, Error: {1}", + "Check the details of the server's message to correct your request.", + InvalidRequestError, + ) AUTHENTICATION_PASSTHROUGH = ( 401, "ATLAN-PYTHON-401-000", diff --git a/pyatlan/generator/templates/methods/asset/collection.jinja2 b/pyatlan/generator/templates/methods/asset/collection.jinja2 new file mode 100644 index 00000000..745fefbe --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/collection.jinja2 @@ -0,0 +1,23 @@ + + @classmethod + @init_guid + def creator(cls, *, client: AtlanClient, name: str) -> Collection: + validate_required_fields(["client", "name"], [client, name]) + return cls(attributes=Collection.Attributes.creator(client=client, name=name)) + + @classmethod + def _generate_qualified_name(cls, client: AtlanClient): + """ + Generate a unique Collection name. + + :param client: connectivity to the Atlan tenant + as the user who will own the Collection + :returns: a unique name for the Collection + """ + try: + username = client.user.get_current().username + return f"default/collection/{username}/{uuid4()}" + except AtlanError as e: + raise ErrorCode.UNABLE_TO_GENERATE_QN.exception_with_parameters( + cls.__name__, e + ) from e diff --git a/pyatlan/generator/templates/methods/asset/folder.jinja2 b/pyatlan/generator/templates/methods/asset/folder.jinja2 new file mode 100644 index 00000000..e7143214 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/folder.jinja2 @@ -0,0 +1,39 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + ) -> Folder: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: str, + ) -> Folder: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Folder: + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + return Folder( + attributes=Folder.Attributes.creator( + name=name, + collection_qualified_name=collection_qualified_name, + parent_folder_qualified_name=parent_folder_qualified_name, + ) + ) diff --git a/pyatlan/generator/templates/methods/asset/query.jinja2 b/pyatlan/generator/templates/methods/asset/query.jinja2 new file mode 100644 index 00000000..1f5f9417 --- /dev/null +++ b/pyatlan/generator/templates/methods/asset/query.jinja2 @@ -0,0 +1,39 @@ + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + ) -> Query: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: str, + ) -> Query: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Query: + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + return Query( + attributes=Query.Attributes.creator( + name=name, + collection_qualified_name=collection_qualified_name, + parent_folder_qualified_name=parent_folder_qualified_name, + ) + ) diff --git a/pyatlan/generator/templates/methods/attribute/collection.jinja2 b/pyatlan/generator/templates/methods/attribute/collection.jinja2 new file mode 100644 index 00000000..1feaa889 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/collection.jinja2 @@ -0,0 +1,14 @@ + + @classmethod + @init_guid + def creator( + cls, + *, + client: AtlanClient, + name: str, + ) -> Collection.Attributes: + validate_required_fields(["name"], [name]) + return Collection.Attributes( + name=name, + qualified_name=Collection._generate_qualified_name(client), + ) diff --git a/pyatlan/generator/templates/methods/attribute/folder.jinja2 b/pyatlan/generator/templates/methods/attribute/folder.jinja2 new file mode 100644 index 00000000..e34fbaf7 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/folder.jinja2 @@ -0,0 +1,33 @@ + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Folder.Attributes: + from pyatlan.model.assets import Collection + + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + + if not parent_folder_qualified_name: + qualified_name = f"{collection_qualified_name}/{name}" + parent_qn = collection_qualified_name + parent = Collection.ref_by_qualified_name(collection_qualified_name) + + else: + qualified_name = f"{parent_folder_qualified_name}/{name}" + parent_qn = parent_folder_qualified_name + parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] + + return Folder.Attributes( + name=name, + qualified_name=qualified_name, + collection_qualified_name=collection_qualified_name, + parent=parent, + parent_qualified_name=parent_qn, + ) diff --git a/pyatlan/generator/templates/methods/attribute/query.jinja2 b/pyatlan/generator/templates/methods/attribute/query.jinja2 new file mode 100644 index 00000000..01ab74a0 --- /dev/null +++ b/pyatlan/generator/templates/methods/attribute/query.jinja2 @@ -0,0 +1,33 @@ + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Query.Attributes: + from pyatlan.model.assets import Collection, Folder + + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + + if not parent_folder_qualified_name: + qualified_name = f"{collection_qualified_name}/{name}" + parent_qn = collection_qualified_name + parent = Collection.ref_by_qualified_name(collection_qualified_name) + + else: + qualified_name = f"{parent_folder_qualified_name}/{name}" + parent_qn = parent_folder_qualified_name + parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] + + return Query.Attributes( + name=name, + qualified_name=qualified_name, + collection_qualified_name=collection_qualified_name, + parent=parent, + parent_qualified_name=parent_qn, + ) diff --git a/pyatlan/model/assets/collection.py b/pyatlan/model/assets/collection.py index 22cad89f..b1399bdf 100644 --- a/pyatlan/model/assets/collection.py +++ b/pyatlan/model/assets/collection.py @@ -5,11 +5,15 @@ from __future__ import annotations from typing import ClassVar, List, Optional +from uuid import uuid4 from pydantic.v1 import Field, validator +from pyatlan.client.atlan import AtlanClient +from pyatlan.errors import AtlanError, ErrorCode from pyatlan.model.enums import IconType from pyatlan.model.fields.atlan_fields import KeywordField, TextField +from pyatlan.utils import init_guid, validate_required_fields from .core.namespace import Namespace @@ -25,6 +29,12 @@ def validate_type_name(cls, v): raise ValueError("must be Collection") return v + @classmethod + @init_guid + def creator(cls, *, client: AtlanClient, name: str) -> Collection: + validate_required_fields(["client", "name"], [client, name]) + return cls(attributes=Collection.Attributes.creator(client=client, name=name)) + def __setattr__(self, name, value): if name in Collection._convenience_properties: return object.__setattr__(self, name, value) @@ -64,10 +74,41 @@ def icon_type(self, icon_type: Optional[IconType]): self.attributes = self.Attributes() self.attributes.icon_type = icon_type + @classmethod + def _generate_qualified_name(cls, client: AtlanClient): + """ + Generate a unique Collection name. + + :param client: connectivity to the Atlan tenant + as the user who will own the Collection + :returns: a unique name for the Collection + """ + try: + username = client.user.get_current().username + return f"default/collection/{username}/{uuid4()}" + except AtlanError as e: + raise ErrorCode.UNABLE_TO_GENERATE_QN.exception_with_parameters( + cls.__name__, e + ) from e + class Attributes(Namespace.Attributes): icon: Optional[str] = Field(default=None, description="") icon_type: Optional[IconType] = Field(default=None, description="") + @classmethod + @init_guid + def creator( + cls, + *, + client: AtlanClient, + name: str, + ) -> Collection.Attributes: + validate_required_fields(["name"], [name]) + return Collection.Attributes( + name=name, + qualified_name=Collection._generate_qualified_name(client), + ) + attributes: Collection.Attributes = Field( default_factory=lambda: Collection.Attributes(), description=( diff --git a/pyatlan/model/assets/core/folder.py b/pyatlan/model/assets/core/folder.py index d833a5a6..c5ae0e61 100644 --- a/pyatlan/model/assets/core/folder.py +++ b/pyatlan/model/assets/core/folder.py @@ -4,11 +4,12 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator from pyatlan.model.fields.atlan_fields import KeywordTextField, RelationField +from pyatlan.utils import init_guid, validate_required_fields from .namespace import Namespace @@ -18,6 +19,45 @@ class Folder(Namespace): type_name: str = Field(default="Folder", allow_mutation=False) + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + ) -> Folder: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: str, + ) -> Folder: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Folder: + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + return Folder( + attributes=Folder.Attributes.creator( + name=name, + collection_qualified_name=collection_qualified_name, + parent_folder_qualified_name=parent_folder_qualified_name, + ) + ) + @validator("type_name") def validate_type_name(cls, v): if v != "Folder": @@ -98,6 +138,39 @@ class Attributes(Namespace.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Folder.Attributes: + from pyatlan.model.assets import Collection + + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + + if not parent_folder_qualified_name: + qualified_name = f"{collection_qualified_name}/{name}" + parent_qn = collection_qualified_name + parent = Collection.ref_by_qualified_name(collection_qualified_name) + + else: + qualified_name = f"{parent_folder_qualified_name}/{name}" + parent_qn = parent_folder_qualified_name + parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] + + return Folder.Attributes( + name=name, + qualified_name=qualified_name, + collection_qualified_name=collection_qualified_name, + parent=parent, + parent_qualified_name=parent_qn, + ) + attributes: Folder.Attributes = Field( default_factory=lambda: Folder.Attributes(), description=( diff --git a/pyatlan/model/assets/core/query.py b/pyatlan/model/assets/core/query.py index 979823ed..2c16de91 100644 --- a/pyatlan/model/assets/core/query.py +++ b/pyatlan/model/assets/core/query.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import ClassVar, List, Optional +from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator @@ -14,6 +14,7 @@ RelationField, TextField, ) +from pyatlan.utils import init_guid, validate_required_fields from .s_q_l import SQL @@ -23,6 +24,45 @@ class Query(SQL): type_name: str = Field(default="Query", allow_mutation=False) + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + ) -> Query: ... + + @overload + @classmethod + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: str, + ) -> Query: ... + + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Query: + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + return Query( + attributes=Query.Attributes.creator( + name=name, + collection_qualified_name=collection_qualified_name, + parent_folder_qualified_name=parent_folder_qualified_name, + ) + ) + @validator("type_name") def validate_type_name(cls, v): if v != "Query": @@ -359,6 +399,39 @@ class Attributes(SQL.Attributes): default=None, description="" ) # relationship + @classmethod + @init_guid + def creator( + cls, + *, + name: str, + collection_qualified_name: str, + parent_folder_qualified_name: Optional[str] = None, + ) -> Query.Attributes: + from pyatlan.model.assets import Collection, Folder + + validate_required_fields( + ["name", "collection_qualified_name"], [name, collection_qualified_name] + ) + + if not parent_folder_qualified_name: + qualified_name = f"{collection_qualified_name}/{name}" + parent_qn = collection_qualified_name + parent = Collection.ref_by_qualified_name(collection_qualified_name) + + else: + qualified_name = f"{parent_folder_qualified_name}/{name}" + parent_qn = parent_folder_qualified_name + parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] + + return Query.Attributes( + name=name, + qualified_name=qualified_name, + collection_qualified_name=collection_qualified_name, + parent=parent, + parent_qualified_name=parent_qn, + ) + attributes: Query.Attributes = Field( default_factory=lambda: Query.Attributes(), description=( From c9e9aedbe772fed1754fceebb55644896dab6ca6 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 30 Dec 2024 18:44:32 +0530 Subject: [PATCH 20/66] [generator] Fixed generator and regenerated latest typedef models --- docs/asset/azureservicebusschema.rst | 10 + docs/asset/bigquerytag.rst | 10 + docs/assets.rst | 2 + pyatlan/generator/templates/imports.jinja2 | 7 +- .../templates/methods/asset/collection.jinja2 | 2 +- .../templates/referenceable_attributes.jinja2 | 9 + .../templates/referenceable_methods.jinja2 | 17 + pyatlan/model/assets/__init__.py | 2 + pyatlan/model/assets/__init__.pyi | 4 + pyatlan/model/assets/azure_service_bus.py | 28 + .../model/assets/azure_service_bus_schema.py | 76 +++ .../model/assets/azure_service_bus_topic.py | 27 + pyatlan/model/assets/bigquery_tag.py | 597 ++++++++++++++++++ pyatlan/model/assets/collection.py | 46 +- pyatlan/model/assets/core/data_contract.py | 3 +- pyatlan/model/assets/core/folder.py | 4 +- pyatlan/model/assets/core/query.py | 4 +- pyatlan/model/assets/core/referenceable.py | 2 +- pyatlan/model/structs.py | 1 + 19 files changed, 817 insertions(+), 34 deletions(-) create mode 100644 docs/asset/azureservicebusschema.rst create mode 100644 docs/asset/bigquerytag.rst create mode 100644 pyatlan/model/assets/azure_service_bus_schema.py create mode 100644 pyatlan/model/assets/bigquery_tag.py diff --git a/docs/asset/azureservicebusschema.rst b/docs/asset/azureservicebusschema.rst new file mode 100644 index 00000000..f07eda52 --- /dev/null +++ b/docs/asset/azureservicebusschema.rst @@ -0,0 +1,10 @@ +.. _azureservicebusschema: + +AzureServiceBusSchema +===================== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: AzureServiceBusSchema + :members: diff --git a/docs/asset/bigquerytag.rst b/docs/asset/bigquerytag.rst new file mode 100644 index 00000000..3ee25841 --- /dev/null +++ b/docs/asset/bigquerytag.rst @@ -0,0 +1,10 @@ +.. _bigquerytag: + +BigqueryTag +=========== + +.. module:: pyatlan.model.assets + :no-index: + +.. autoclass:: BigqueryTag + :members: diff --git a/docs/assets.rst b/docs/assets.rst index 6d610bc0..7e87e694 100644 --- a/docs/assets.rst +++ b/docs/assets.rst @@ -54,10 +54,12 @@ You can interact with all of the following different kinds of assets: asset/azureeventhubconsumergroup asset/azureservicebus asset/azureservicebusnamespace + asset/azureservicebusschema asset/azureservicebustopic asset/bi asset/biprocess asset/badge + asset/bigquerytag asset/businesspolicy asset/businesspolicyexception asset/businesspolicyincident diff --git a/pyatlan/generator/templates/imports.jinja2 b/pyatlan/generator/templates/imports.jinja2 index f4d7e03e..9159babb 100644 --- a/pyatlan/generator/templates/imports.jinja2 +++ b/pyatlan/generator/templates/imports.jinja2 @@ -3,8 +3,8 @@ from __future__ import annotations import hashlib import sys import uuid -from json import loads -from json.decoder import JSONDecodeError +from uuid import uuid4 +from json import JSONDecodeError, loads from datetime import datetime from io import StringIO from typing import Any, ClassVar, Dict, List, Optional, Set, Type, TypeVar, TYPE_CHECKING, cast, overload, Union @@ -14,7 +14,7 @@ from urllib.parse import quote, unquote from pydantic.v1 import Field, PrivateAttr, StrictStr, root_validator, validator -from pyatlan.errors import ErrorCode +from pyatlan.errors import AtlanError, ErrorCode from pyatlan.model.core import Announcement, AtlanObject, AtlanTag, AtlanTagName, Meaning from pyatlan.model.custom_metadata import CustomMetadataDict, CustomMetadataProxy from pyatlan.model.enums import ( @@ -116,3 +116,4 @@ from pyatlan.utils import ( from pyatlan.model.data_mesh import DataProductsAssetsDSL from pyatlan.model.contract import DataContractSpec from pyatlan.model.lineage_ref import LineageRef +from pyatlan.client.atlan import AtlanClient diff --git a/pyatlan/generator/templates/methods/asset/collection.jinja2 b/pyatlan/generator/templates/methods/asset/collection.jinja2 index 745fefbe..46100a6c 100644 --- a/pyatlan/generator/templates/methods/asset/collection.jinja2 +++ b/pyatlan/generator/templates/methods/asset/collection.jinja2 @@ -5,7 +5,7 @@ validate_required_fields(["client", "name"], [client, name]) return cls(attributes=Collection.Attributes.creator(client=client, name=name)) - @classmethod + @classmethod def _generate_qualified_name(cls, client: AtlanClient): """ Generate a unique Collection name. diff --git a/pyatlan/generator/templates/referenceable_attributes.jinja2 b/pyatlan/generator/templates/referenceable_attributes.jinja2 index d1a01c5c..892a94aa 100644 --- a/pyatlan/generator/templates/referenceable_attributes.jinja2 +++ b/pyatlan/generator/templates/referenceable_attributes.jinja2 @@ -77,7 +77,16 @@ QUALIFIED_NAME: ClassVar[KeywordTextField] = KeywordTextField( "qualifiedName", "qualifiedName", "qualifiedName.text" ) + """Unique fully-qualified name of the asset in Atlan.""" + CUSTOM_ATTRIBUTES: ClassVar[TextField] = TextField( + "__customAttributes", "__customAttributes" + ) + """ + Any source-provided custom information. + NOTE: This is NOT the same as custom metadata (user-managed), + but is an entirely different area of source-managed custom information. + """ type_name: str = Field(default="Referenceable", description='Name of the type definition that defines this instance.' ) diff --git a/pyatlan/generator/templates/referenceable_methods.jinja2 b/pyatlan/generator/templates/referenceable_methods.jinja2 index 2e4484b1..693e4518 100644 --- a/pyatlan/generator/templates/referenceable_methods.jinja2 +++ b/pyatlan/generator/templates/referenceable_methods.jinja2 @@ -6,6 +6,23 @@ __pydantic_self__.business_attributes ) + @root_validator(pre=True) + def parse_custom_attributes(cls, values): + if "attributes" in values: + attributes = values["attributes"] + if "__customAttributes" in attributes: + # Pop the __customAttributes from attributes + custom_attributes = attributes.pop("__customAttributes") + try: + # Try to parse the JSON string if it's a string + if isinstance(custom_attributes, str): + custom_attributes = loads(custom_attributes) + # Add the parsed custom attributes to the Column + values["custom_attributes"] = custom_attributes + except JSONDecodeError: + pass + return values + def json(self, *args, **kwargs) -> str: self.business_attributes = self._metadata_proxy.business_attributes return super().json(**kwargs) diff --git a/pyatlan/model/assets/__init__.py b/pyatlan/model/assets/__init__.py index 3dc9df50..990d2d38 100644 --- a/pyatlan/model/assets/__init__.py +++ b/pyatlan/model/assets/__init__.py @@ -168,6 +168,7 @@ "cube_hierarchy": ["CubeHierarchy"], "cube_field": ["CubeField"], "cube_dimension": ["CubeDimension"], + "bigquery_tag": ["BigqueryTag"], "kafka": ["Kafka"], "azure_service_bus": ["AzureServiceBus"], "dynamo_d_b": ["DynamoDB"], @@ -299,6 +300,7 @@ "kafka_topic": ["KafkaTopic"], "kafka_consumer_group": ["KafkaConsumerGroup"], "azure_service_bus_namespace": ["AzureServiceBusNamespace"], + "azure_service_bus_schema": ["AzureServiceBusSchema"], "azure_service_bus_topic": ["AzureServiceBusTopic"], "qlik_stream": ["QlikStream"], "dynamo_d_b_local_secondary_index": ["DynamoDBLocalSecondaryIndex"], diff --git a/pyatlan/model/assets/__init__.pyi b/pyatlan/model/assets/__init__.pyi index f91d0ccd..6de75064 100644 --- a/pyatlan/model/assets/__init__.pyi +++ b/pyatlan/model/assets/__init__.pyi @@ -165,6 +165,7 @@ __all__ = [ "CubeHierarchy", "CubeField", "CubeDimension", + "BigqueryTag", "Kafka", "AzureServiceBus", "DynamoDB", @@ -296,6 +297,7 @@ __all__ = [ "KafkaTopic", "KafkaConsumerGroup", "AzureServiceBusNamespace", + "AzureServiceBusSchema", "AzureServiceBusTopic", "QlikStream", "DynamoDBLocalSecondaryIndex", @@ -331,8 +333,10 @@ from .azure_event_hub import AzureEventHub from .azure_event_hub_consumer_group import AzureEventHubConsumerGroup from .azure_service_bus import AzureServiceBus from .azure_service_bus_namespace import AzureServiceBusNamespace +from .azure_service_bus_schema import AzureServiceBusSchema from .azure_service_bus_topic import AzureServiceBusTopic from .badge import Badge +from .bigquery_tag import BigqueryTag from .business_policy import BusinessPolicy from .business_policy_exception import BusinessPolicyException from .business_policy_incident import BusinessPolicyIncident diff --git a/pyatlan/model/assets/azure_service_bus.py b/pyatlan/model/assets/azure_service_bus.py index 55b5efa1..6c370e27 100644 --- a/pyatlan/model/assets/azure_service_bus.py +++ b/pyatlan/model/assets/azure_service_bus.py @@ -43,10 +43,17 @@ def __setattr__(self, name, value): """ Simple name of the AzureServiceBus Namespace in which this asset exists. """ + AZURE_SERVICE_BUS_SCHEMA_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "azureServiceBusSchemaQualifiedName", "azureServiceBusSchemaQualifiedName" + ) + """ + Unique name of the AzureServiceBus Schema in which this asset exists. + """ _convenience_properties: ClassVar[List[str]] = [ "azure_service_bus_namespace_qualified_name", "azure_service_bus_namespace_name", + "azure_service_bus_schema_qualified_name", ] @property @@ -85,6 +92,24 @@ def azure_service_bus_namespace_name( azure_service_bus_namespace_name ) + @property + def azure_service_bus_schema_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.azure_service_bus_schema_qualified_name + ) + + @azure_service_bus_schema_qualified_name.setter + def azure_service_bus_schema_qualified_name( + self, azure_service_bus_schema_qualified_name: Optional[str] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.azure_service_bus_schema_qualified_name = ( + azure_service_bus_schema_qualified_name + ) + class Attributes(EventStore.Attributes): azure_service_bus_namespace_qualified_name: Optional[str] = Field( default=None, description="" @@ -92,6 +117,9 @@ class Attributes(EventStore.Attributes): azure_service_bus_namespace_name: Optional[str] = Field( default=None, description="" ) + azure_service_bus_schema_qualified_name: Optional[str] = Field( + default=None, description="" + ) attributes: AzureServiceBus.Attributes = Field( default_factory=lambda: AzureServiceBus.Attributes(), diff --git a/pyatlan/model/assets/azure_service_bus_schema.py b/pyatlan/model/assets/azure_service_bus_schema.py new file mode 100644 index 00000000..59074ae1 --- /dev/null +++ b/pyatlan/model/assets/azure_service_bus_schema.py @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from typing import ClassVar, List, Optional + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import RelationField + +from .azure_service_bus import AzureServiceBus + + +class AzureServiceBusSchema(AzureServiceBus): + """Description""" + + type_name: str = Field(default="AzureServiceBusSchema", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "AzureServiceBusSchema": + raise ValueError("must be AzureServiceBusSchema") + return v + + def __setattr__(self, name, value): + if name in AzureServiceBusSchema._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + AZURE_SERVICE_BUS_TOPICS: ClassVar[RelationField] = RelationField( + "azureServiceBusTopics" + ) + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "azure_service_bus_topics", + ] + + @property + def azure_service_bus_topics(self) -> Optional[List[AzureServiceBusTopic]]: + return ( + None + if self.attributes is None + else self.attributes.azure_service_bus_topics + ) + + @azure_service_bus_topics.setter + def azure_service_bus_topics( + self, azure_service_bus_topics: Optional[List[AzureServiceBusTopic]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.azure_service_bus_topics = azure_service_bus_topics + + class Attributes(AzureServiceBus.Attributes): + azure_service_bus_topics: Optional[List[AzureServiceBusTopic]] = Field( + default=None, description="" + ) # relationship + + attributes: AzureServiceBusSchema.Attributes = Field( + default_factory=lambda: AzureServiceBusSchema.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .azure_service_bus_topic import AzureServiceBusTopic # noqa + +AzureServiceBusSchema.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/azure_service_bus_topic.py b/pyatlan/model/assets/azure_service_bus_topic.py index 8bc272d8..7c379178 100644 --- a/pyatlan/model/assets/azure_service_bus_topic.py +++ b/pyatlan/model/assets/azure_service_bus_topic.py @@ -29,6 +29,12 @@ def __setattr__(self, name, value): return object.__setattr__(self, name, value) super().__setattr__(name, value) + AZURE_SERVICE_BUS_SCHEMAS: ClassVar[RelationField] = RelationField( + "azureServiceBusSchemas" + ) + """ + TBC + """ AZURE_SERVICE_BUS_NAMESPACE: ClassVar[RelationField] = RelationField( "azureServiceBusNamespace" ) @@ -37,9 +43,26 @@ def __setattr__(self, name, value): """ _convenience_properties: ClassVar[List[str]] = [ + "azure_service_bus_schemas", "azure_service_bus_namespace", ] + @property + def azure_service_bus_schemas(self) -> Optional[List[AzureServiceBusSchema]]: + return ( + None + if self.attributes is None + else self.attributes.azure_service_bus_schemas + ) + + @azure_service_bus_schemas.setter + def azure_service_bus_schemas( + self, azure_service_bus_schemas: Optional[List[AzureServiceBusSchema]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.azure_service_bus_schemas = azure_service_bus_schemas + @property def azure_service_bus_namespace(self) -> Optional[AzureServiceBusNamespace]: return ( @@ -57,6 +80,9 @@ def azure_service_bus_namespace( self.attributes.azure_service_bus_namespace = azure_service_bus_namespace class Attributes(AzureServiceBus.Attributes): + azure_service_bus_schemas: Optional[List[AzureServiceBusSchema]] = Field( + default=None, description="" + ) # relationship azure_service_bus_namespace: Optional[AzureServiceBusNamespace] = Field( default=None, description="" ) # relationship @@ -72,5 +98,6 @@ class Attributes(AzureServiceBus.Attributes): from .azure_service_bus_namespace import AzureServiceBusNamespace # noqa +from .azure_service_bus_schema import AzureServiceBusSchema # noqa AzureServiceBusTopic.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/bigquery_tag.py b/pyatlan/model/assets/bigquery_tag.py new file mode 100644 index 00000000..98b9c715 --- /dev/null +++ b/pyatlan/model/assets/bigquery_tag.py @@ -0,0 +1,597 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Atlan Pte. Ltd. + + +from __future__ import annotations + +from datetime import datetime +from typing import ClassVar, Dict, List, Optional, Set + +from pydantic.v1 import Field, validator + +from pyatlan.model.fields.atlan_fields import ( + BooleanField, + KeywordField, + KeywordTextField, + NumericField, + RelationField, +) +from pyatlan.model.structs import SourceTagAttribute + +from .core.tag import Tag + + +class BigqueryTag(Tag): + """Description""" + + type_name: str = Field(default="BigqueryTag", allow_mutation=False) + + @validator("type_name") + def validate_type_name(cls, v): + if v != "BigqueryTag": + raise ValueError("must be BigqueryTag") + return v + + def __setattr__(self, name, value): + if name in BigqueryTag._convenience_properties: + return object.__setattr__(self, name, value) + super().__setattr__(name, value) + + BIGQUERY_TAG_TYPE: ClassVar[KeywordField] = KeywordField( + "bigqueryTagType", "bigqueryTagType" + ) + """ + The specific type or category of the Bigquery tag, which can be used for classification and organization of Bigquery assets. + """ # noqa: E501 + BIGQUERY_TAG_HIERARCHY: ClassVar[KeywordField] = KeywordField( + "bigqueryTagHierarchy", "bigqueryTagHierarchy" + ) + """ + List of top-level upstream nested bigquery tags. + """ + BIGQUERY_TAG_TAXONOMY_PROPERTIES: ClassVar[KeywordField] = KeywordField( + "bigqueryTagTaxonomyProperties", "bigqueryTagTaxonomyProperties" + ) + """ + Properties of the bigquery tag taxonomy attribute. + """ + TAG_ID: ClassVar[KeywordField] = KeywordField("tagId", "tagId") + """ + Unique identifier of the tag in the source system. + """ + TAG_ATTRIBUTES: ClassVar[KeywordField] = KeywordField( + "tagAttributes", "tagAttributes" + ) + """ + Attributes associated with the tag in the source system. + """ + TAG_ALLOWED_VALUES: ClassVar[KeywordTextField] = KeywordTextField( + "tagAllowedValues", "tagAllowedValues", "tagAllowedValues.text" + ) + """ + Allowed values for the tag in the source system. These are denormalized from tagAttributes for ease of querying. + """ + MAPPED_CLASSIFICATION_NAME: ClassVar[KeywordField] = KeywordField( + "mappedClassificationName", "mappedClassificationName" + ) + """ + Name of the classification in Atlan that is mapped to this tag. + """ + QUERY_COUNT: ClassVar[NumericField] = NumericField("queryCount", "queryCount") + """ + Number of times this asset has been queried. + """ + QUERY_USER_COUNT: ClassVar[NumericField] = NumericField( + "queryUserCount", "queryUserCount" + ) + """ + Number of unique users who have queried this asset. + """ + QUERY_USER_MAP: ClassVar[KeywordField] = KeywordField( + "queryUserMap", "queryUserMap" + ) + """ + Map of unique users who have queried this asset to the number of times they have queried it. + """ + QUERY_COUNT_UPDATED_AT: ClassVar[NumericField] = NumericField( + "queryCountUpdatedAt", "queryCountUpdatedAt" + ) + """ + Time (epoch) at which the query count was last updated, in milliseconds. + """ + DATABASE_NAME: ClassVar[KeywordTextField] = KeywordTextField( + "databaseName", "databaseName.keyword", "databaseName" + ) + """ + Simple name of the database in which this SQL asset exists, or empty if it does not exist within a database. + """ + DATABASE_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "databaseQualifiedName", "databaseQualifiedName" + ) + """ + Unique name of the database in which this SQL asset exists, or empty if it does not exist within a database. + """ + SCHEMA_NAME: ClassVar[KeywordTextField] = KeywordTextField( + "schemaName", "schemaName.keyword", "schemaName" + ) + """ + Simple name of the schema in which this SQL asset exists, or empty if it does not exist within a schema. + """ + SCHEMA_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "schemaQualifiedName", "schemaQualifiedName" + ) + """ + Unique name of the schema in which this SQL asset exists, or empty if it does not exist within a schema. + """ + TABLE_NAME: ClassVar[KeywordTextField] = KeywordTextField( + "tableName", "tableName.keyword", "tableName" + ) + """ + Simple name of the table in which this SQL asset exists, or empty if it does not exist within a table. + """ + TABLE_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "tableQualifiedName", "tableQualifiedName" + ) + """ + Unique name of the table in which this SQL asset exists, or empty if it does not exist within a table. + """ + VIEW_NAME: ClassVar[KeywordTextField] = KeywordTextField( + "viewName", "viewName.keyword", "viewName" + ) + """ + Simple name of the view in which this SQL asset exists, or empty if it does not exist within a view. + """ + VIEW_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "viewQualifiedName", "viewQualifiedName" + ) + """ + Unique name of the view in which this SQL asset exists, or empty if it does not exist within a view. + """ + CALCULATION_VIEW_NAME: ClassVar[KeywordTextField] = KeywordTextField( + "calculationViewName", "calculationViewName.keyword", "calculationViewName" + ) + """ + Simple name of the calculation view in which this SQL asset exists, or empty if it does not exist within a calculation view. + """ # noqa: E501 + CALCULATION_VIEW_QUALIFIED_NAME: ClassVar[KeywordField] = KeywordField( + "calculationViewQualifiedName", "calculationViewQualifiedName" + ) + """ + Unique name of the calculation view in which this SQL asset exists, or empty if it does not exist within a calculation view. + """ # noqa: E501 + IS_PROFILED: ClassVar[BooleanField] = BooleanField("isProfiled", "isProfiled") + """ + Whether this asset has been profiled (true) or not (false). + """ + LAST_PROFILED_AT: ClassVar[NumericField] = NumericField( + "lastProfiledAt", "lastProfiledAt" + ) + """ + Time (epoch) at which this asset was last profiled, in milliseconds. + """ + + DBT_SOURCES: ClassVar[RelationField] = RelationField("dbtSources") + """ + TBC + """ + SQL_DBT_MODELS: ClassVar[RelationField] = RelationField("sqlDbtModels") + """ + TBC + """ + DBT_TESTS: ClassVar[RelationField] = RelationField("dbtTests") + """ + TBC + """ + SQL_DBT_SOURCES: ClassVar[RelationField] = RelationField("sqlDBTSources") + """ + TBC + """ + DBT_MODELS: ClassVar[RelationField] = RelationField("dbtModels") + """ + TBC + """ + + _convenience_properties: ClassVar[List[str]] = [ + "bigquery_tag_type", + "bigquery_tag_hierarchy", + "bigquery_tag_taxonomy_properties", + "tag_id", + "tag_attributes", + "tag_allowed_values", + "mapped_atlan_tag_name", + "query_count", + "query_user_count", + "query_user_map", + "query_count_updated_at", + "database_name", + "database_qualified_name", + "schema_name", + "schema_qualified_name", + "table_name", + "table_qualified_name", + "view_name", + "view_qualified_name", + "calculation_view_name", + "calculation_view_qualified_name", + "is_profiled", + "last_profiled_at", + "dbt_sources", + "sql_dbt_models", + "dbt_tests", + "sql_dbt_sources", + "dbt_models", + ] + + @property + def bigquery_tag_type(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.bigquery_tag_type + + @bigquery_tag_type.setter + def bigquery_tag_type(self, bigquery_tag_type: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.bigquery_tag_type = bigquery_tag_type + + @property + def bigquery_tag_hierarchy(self) -> Optional[List[Dict[str, str]]]: + return ( + None if self.attributes is None else self.attributes.bigquery_tag_hierarchy + ) + + @bigquery_tag_hierarchy.setter + def bigquery_tag_hierarchy( + self, bigquery_tag_hierarchy: Optional[List[Dict[str, str]]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.bigquery_tag_hierarchy = bigquery_tag_hierarchy + + @property + def bigquery_tag_taxonomy_properties(self) -> Optional[Dict[str, str]]: + return ( + None + if self.attributes is None + else self.attributes.bigquery_tag_taxonomy_properties + ) + + @bigquery_tag_taxonomy_properties.setter + def bigquery_tag_taxonomy_properties( + self, bigquery_tag_taxonomy_properties: Optional[Dict[str, str]] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.bigquery_tag_taxonomy_properties = ( + bigquery_tag_taxonomy_properties + ) + + @property + def tag_id(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.tag_id + + @tag_id.setter + def tag_id(self, tag_id: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.tag_id = tag_id + + @property + def tag_attributes(self) -> Optional[List[SourceTagAttribute]]: + return None if self.attributes is None else self.attributes.tag_attributes + + @tag_attributes.setter + def tag_attributes(self, tag_attributes: Optional[List[SourceTagAttribute]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.tag_attributes = tag_attributes + + @property + def tag_allowed_values(self) -> Optional[Set[str]]: + return None if self.attributes is None else self.attributes.tag_allowed_values + + @tag_allowed_values.setter + def tag_allowed_values(self, tag_allowed_values: Optional[Set[str]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.tag_allowed_values = tag_allowed_values + + @property + def mapped_atlan_tag_name(self) -> Optional[str]: + return ( + None if self.attributes is None else self.attributes.mapped_atlan_tag_name + ) + + @mapped_atlan_tag_name.setter + def mapped_atlan_tag_name(self, mapped_atlan_tag_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.mapped_atlan_tag_name = mapped_atlan_tag_name + + @property + def query_count(self) -> Optional[int]: + return None if self.attributes is None else self.attributes.query_count + + @query_count.setter + def query_count(self, query_count: Optional[int]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.query_count = query_count + + @property + def query_user_count(self) -> Optional[int]: + return None if self.attributes is None else self.attributes.query_user_count + + @query_user_count.setter + def query_user_count(self, query_user_count: Optional[int]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.query_user_count = query_user_count + + @property + def query_user_map(self) -> Optional[Dict[str, int]]: + return None if self.attributes is None else self.attributes.query_user_map + + @query_user_map.setter + def query_user_map(self, query_user_map: Optional[Dict[str, int]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.query_user_map = query_user_map + + @property + def query_count_updated_at(self) -> Optional[datetime]: + return ( + None if self.attributes is None else self.attributes.query_count_updated_at + ) + + @query_count_updated_at.setter + def query_count_updated_at(self, query_count_updated_at: Optional[datetime]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.query_count_updated_at = query_count_updated_at + + @property + def database_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.database_name + + @database_name.setter + def database_name(self, database_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.database_name = database_name + + @property + def database_qualified_name(self) -> Optional[str]: + return ( + None if self.attributes is None else self.attributes.database_qualified_name + ) + + @database_qualified_name.setter + def database_qualified_name(self, database_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.database_qualified_name = database_qualified_name + + @property + def schema_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.schema_name + + @schema_name.setter + def schema_name(self, schema_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.schema_name = schema_name + + @property + def schema_qualified_name(self) -> Optional[str]: + return ( + None if self.attributes is None else self.attributes.schema_qualified_name + ) + + @schema_qualified_name.setter + def schema_qualified_name(self, schema_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.schema_qualified_name = schema_qualified_name + + @property + def table_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.table_name + + @table_name.setter + def table_name(self, table_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.table_name = table_name + + @property + def table_qualified_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.table_qualified_name + + @table_qualified_name.setter + def table_qualified_name(self, table_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.table_qualified_name = table_qualified_name + + @property + def view_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.view_name + + @view_name.setter + def view_name(self, view_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.view_name = view_name + + @property + def view_qualified_name(self) -> Optional[str]: + return None if self.attributes is None else self.attributes.view_qualified_name + + @view_qualified_name.setter + def view_qualified_name(self, view_qualified_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.view_qualified_name = view_qualified_name + + @property + def calculation_view_name(self) -> Optional[str]: + return ( + None if self.attributes is None else self.attributes.calculation_view_name + ) + + @calculation_view_name.setter + def calculation_view_name(self, calculation_view_name: Optional[str]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.calculation_view_name = calculation_view_name + + @property + def calculation_view_qualified_name(self) -> Optional[str]: + return ( + None + if self.attributes is None + else self.attributes.calculation_view_qualified_name + ) + + @calculation_view_qualified_name.setter + def calculation_view_qualified_name( + self, calculation_view_qualified_name: Optional[str] + ): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.calculation_view_qualified_name = ( + calculation_view_qualified_name + ) + + @property + def is_profiled(self) -> Optional[bool]: + return None if self.attributes is None else self.attributes.is_profiled + + @is_profiled.setter + def is_profiled(self, is_profiled: Optional[bool]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.is_profiled = is_profiled + + @property + def last_profiled_at(self) -> Optional[datetime]: + return None if self.attributes is None else self.attributes.last_profiled_at + + @last_profiled_at.setter + def last_profiled_at(self, last_profiled_at: Optional[datetime]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.last_profiled_at = last_profiled_at + + @property + def dbt_sources(self) -> Optional[List[DbtSource]]: + return None if self.attributes is None else self.attributes.dbt_sources + + @dbt_sources.setter + def dbt_sources(self, dbt_sources: Optional[List[DbtSource]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.dbt_sources = dbt_sources + + @property + def sql_dbt_models(self) -> Optional[List[DbtModel]]: + return None if self.attributes is None else self.attributes.sql_dbt_models + + @sql_dbt_models.setter + def sql_dbt_models(self, sql_dbt_models: Optional[List[DbtModel]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.sql_dbt_models = sql_dbt_models + + @property + def dbt_tests(self) -> Optional[List[DbtTest]]: + return None if self.attributes is None else self.attributes.dbt_tests + + @dbt_tests.setter + def dbt_tests(self, dbt_tests: Optional[List[DbtTest]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.dbt_tests = dbt_tests + + @property + def sql_dbt_sources(self) -> Optional[List[DbtSource]]: + return None if self.attributes is None else self.attributes.sql_dbt_sources + + @sql_dbt_sources.setter + def sql_dbt_sources(self, sql_dbt_sources: Optional[List[DbtSource]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.sql_dbt_sources = sql_dbt_sources + + @property + def dbt_models(self) -> Optional[List[DbtModel]]: + return None if self.attributes is None else self.attributes.dbt_models + + @dbt_models.setter + def dbt_models(self, dbt_models: Optional[List[DbtModel]]): + if self.attributes is None: + self.attributes = self.Attributes() + self.attributes.dbt_models = dbt_models + + class Attributes(Tag.Attributes): + bigquery_tag_type: Optional[str] = Field(default=None, description="") + bigquery_tag_hierarchy: Optional[List[Dict[str, str]]] = Field( + default=None, description="" + ) + bigquery_tag_taxonomy_properties: Optional[Dict[str, str]] = Field( + default=None, description="" + ) + tag_id: Optional[str] = Field(default=None, description="") + tag_attributes: Optional[List[SourceTagAttribute]] = Field( + default=None, description="" + ) + tag_allowed_values: Optional[Set[str]] = Field(default=None, description="") + mapped_atlan_tag_name: Optional[str] = Field(default=None, description="") + query_count: Optional[int] = Field(default=None, description="") + query_user_count: Optional[int] = Field(default=None, description="") + query_user_map: Optional[Dict[str, int]] = Field(default=None, description="") + query_count_updated_at: Optional[datetime] = Field(default=None, description="") + database_name: Optional[str] = Field(default=None, description="") + database_qualified_name: Optional[str] = Field(default=None, description="") + schema_name: Optional[str] = Field(default=None, description="") + schema_qualified_name: Optional[str] = Field(default=None, description="") + table_name: Optional[str] = Field(default=None, description="") + table_qualified_name: Optional[str] = Field(default=None, description="") + view_name: Optional[str] = Field(default=None, description="") + view_qualified_name: Optional[str] = Field(default=None, description="") + calculation_view_name: Optional[str] = Field(default=None, description="") + calculation_view_qualified_name: Optional[str] = Field( + default=None, description="" + ) + is_profiled: Optional[bool] = Field(default=None, description="") + last_profiled_at: Optional[datetime] = Field(default=None, description="") + dbt_sources: Optional[List[DbtSource]] = Field( + default=None, description="" + ) # relationship + sql_dbt_models: Optional[List[DbtModel]] = Field( + default=None, description="" + ) # relationship + dbt_tests: Optional[List[DbtTest]] = Field( + default=None, description="" + ) # relationship + sql_dbt_sources: Optional[List[DbtSource]] = Field( + default=None, description="" + ) # relationship + dbt_models: Optional[List[DbtModel]] = Field( + default=None, description="" + ) # relationship + + attributes: BigqueryTag.Attributes = Field( + default_factory=lambda: BigqueryTag.Attributes(), + description=( + "Map of attributes in the instance and their values. " + "The specific keys of this map will vary by type, " + "so are described in the sub-types of this schema." + ), + ) + + +from .core.dbt_model import DbtModel # noqa +from .core.dbt_source import DbtSource # noqa +from .core.dbt_test import DbtTest # noqa + +BigqueryTag.Attributes.update_forward_refs() diff --git a/pyatlan/model/assets/collection.py b/pyatlan/model/assets/collection.py index b1399bdf..1c308642 100644 --- a/pyatlan/model/assets/collection.py +++ b/pyatlan/model/assets/collection.py @@ -21,6 +21,29 @@ class Collection(Namespace): """Description""" + @classmethod + @init_guid + def creator(cls, *, client: AtlanClient, name: str) -> Collection: + validate_required_fields(["client", "name"], [client, name]) + return cls(attributes=Collection.Attributes.creator(client=client, name=name)) + + @classmethod + def _generate_qualified_name(cls, client: AtlanClient): + """ + Generate a unique Collection name. + + :param client: connectivity to the Atlan tenant + as the user who will own the Collection + :returns: a unique name for the Collection + """ + try: + username = client.user.get_current().username + return f"default/collection/{username}/{uuid4()}" + except AtlanError as e: + raise ErrorCode.UNABLE_TO_GENERATE_QN.exception_with_parameters( + cls.__name__, e + ) from e + type_name: str = Field(default="Collection", allow_mutation=False) @validator("type_name") @@ -29,12 +52,6 @@ def validate_type_name(cls, v): raise ValueError("must be Collection") return v - @classmethod - @init_guid - def creator(cls, *, client: AtlanClient, name: str) -> Collection: - validate_required_fields(["client", "name"], [client, name]) - return cls(attributes=Collection.Attributes.creator(client=client, name=name)) - def __setattr__(self, name, value): if name in Collection._convenience_properties: return object.__setattr__(self, name, value) @@ -74,23 +91,6 @@ def icon_type(self, icon_type: Optional[IconType]): self.attributes = self.Attributes() self.attributes.icon_type = icon_type - @classmethod - def _generate_qualified_name(cls, client: AtlanClient): - """ - Generate a unique Collection name. - - :param client: connectivity to the Atlan tenant - as the user who will own the Collection - :returns: a unique name for the Collection - """ - try: - username = client.user.get_current().username - return f"default/collection/{username}/{uuid4()}" - except AtlanError as e: - raise ErrorCode.UNABLE_TO_GENERATE_QN.exception_with_parameters( - cls.__name__, e - ) from e - class Attributes(Namespace.Attributes): icon: Optional[str] = Field(default=None, description="") icon_type: Optional[IconType] = Field(default=None, description="") diff --git a/pyatlan/model/assets/core/data_contract.py b/pyatlan/model/assets/core/data_contract.py index 8f5af6af..b0281eab 100644 --- a/pyatlan/model/assets/core/data_contract.py +++ b/pyatlan/model/assets/core/data_contract.py @@ -4,8 +4,7 @@ from __future__ import annotations -from json import loads -from json.decoder import JSONDecodeError +from json import JSONDecodeError, loads from typing import ClassVar, List, Optional, Union, overload from pydantic.v1 import Field, validator diff --git a/pyatlan/model/assets/core/folder.py b/pyatlan/model/assets/core/folder.py index c5ae0e61..18e7e845 100644 --- a/pyatlan/model/assets/core/folder.py +++ b/pyatlan/model/assets/core/folder.py @@ -17,8 +17,6 @@ class Folder(Namespace): """Description""" - type_name: str = Field(default="Folder", allow_mutation=False) - @overload @classmethod def creator( @@ -58,6 +56,8 @@ def creator( ) ) + type_name: str = Field(default="Folder", allow_mutation=False) + @validator("type_name") def validate_type_name(cls, v): if v != "Folder": diff --git a/pyatlan/model/assets/core/query.py b/pyatlan/model/assets/core/query.py index 2c16de91..df137888 100644 --- a/pyatlan/model/assets/core/query.py +++ b/pyatlan/model/assets/core/query.py @@ -22,8 +22,6 @@ class Query(SQL): """Description""" - type_name: str = Field(default="Query", allow_mutation=False) - @overload @classmethod def creator( @@ -63,6 +61,8 @@ def creator( ) ) + type_name: str = Field(default="Query", allow_mutation=False) + @validator("type_name") def validate_type_name(cls, v): if v != "Query": diff --git a/pyatlan/model/assets/core/referenceable.py b/pyatlan/model/assets/core/referenceable.py index 7f903405..33fa2f03 100644 --- a/pyatlan/model/assets/core/referenceable.py +++ b/pyatlan/model/assets/core/referenceable.py @@ -239,8 +239,8 @@ def validate_required(self): QUALIFIED_NAME: ClassVar[KeywordTextField] = KeywordTextField( "qualifiedName", "qualifiedName", "qualifiedName.text" ) - """Unique fully-qualified name of the asset in Atlan.""" + """Unique fully-qualified name of the asset in Atlan.""" CUSTOM_ATTRIBUTES: ClassVar[TextField] = TextField( "__customAttributes", "__customAttributes" ) diff --git a/pyatlan/model/structs.py b/pyatlan/model/structs.py index 653d351d..f72bdd76 100644 --- a/pyatlan/model/structs.py +++ b/pyatlan/model/structs.py @@ -164,6 +164,7 @@ class SourceTagAttachment(AtlanObject): is_source_tag_synced: Optional[bool] = Field(default=None, description="") source_tag_sync_timestamp: Optional[datetime] = Field(default=None, description="") source_tag_sync_error: Optional[str] = Field(default=None, description="") + source_tag_type: Optional[str] = Field(default=None, description="") @classmethod def by_name( From 40b62e38c82009deb1f523c1ae52d940d8f0a4aa Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 00:34:29 +0530 Subject: [PATCH 21/66] [change] Fixed creators and added updater for `Query` asset --- pyatlan/generator/templates/imports.jinja2 | 3 +- .../templates/methods/asset/folder.jinja2 | 7 +- .../templates/methods/asset/query.jinja2 | 61 ++++++++++++-- .../templates/methods/attribute/folder.jinja2 | 17 +++- .../templates/methods/attribute/query.jinja2 | 17 +++- pyatlan/model/assets/core/folder.py | 24 +++--- pyatlan/model/assets/core/query.py | 81 ++++++++++++++++--- 7 files changed, 173 insertions(+), 37 deletions(-) diff --git a/pyatlan/generator/templates/imports.jinja2 b/pyatlan/generator/templates/imports.jinja2 index 9159babb..bd0a93f3 100644 --- a/pyatlan/generator/templates/imports.jinja2 +++ b/pyatlan/generator/templates/imports.jinja2 @@ -4,7 +4,8 @@ import hashlib import sys import uuid from uuid import uuid4 -from json import JSONDecodeError, loads +from base64 import b64encode +from json import JSONDecodeError, loads, dumps from datetime import datetime from io import StringIO from typing import Any, ClassVar, Dict, List, Optional, Set, Type, TypeVar, TYPE_CHECKING, cast, overload, Union diff --git a/pyatlan/generator/templates/methods/asset/folder.jinja2 b/pyatlan/generator/templates/methods/asset/folder.jinja2 index e7143214..0dbea3c0 100644 --- a/pyatlan/generator/templates/methods/asset/folder.jinja2 +++ b/pyatlan/generator/templates/methods/asset/folder.jinja2 @@ -14,7 +14,6 @@ cls, *, name: str, - collection_qualified_name: str, parent_folder_qualified_name: str, ) -> Folder: ... @@ -24,12 +23,10 @@ cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Folder: - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) return Folder( attributes=Folder.Attributes.creator( name=name, diff --git a/pyatlan/generator/templates/methods/asset/query.jinja2 b/pyatlan/generator/templates/methods/asset/query.jinja2 index 1f5f9417..7d206909 100644 --- a/pyatlan/generator/templates/methods/asset/query.jinja2 +++ b/pyatlan/generator/templates/methods/asset/query.jinja2 @@ -14,7 +14,6 @@ cls, *, name: str, - collection_qualified_name: str, parent_folder_qualified_name: str, ) -> Query: ... @@ -24,12 +23,10 @@ cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Query: - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) return Query( attributes=Query.Attributes.creator( name=name, @@ -37,3 +34,57 @@ parent_folder_qualified_name=parent_folder_qualified_name, ) ) + + @classmethod + @init_guid + def updater( + cls, + *, + name: str, + qualified_name: str, + collection_qualified_name: str, + parent_qualified_name: str, + ) -> Query: + from pyatlan.model.assets import Collection, Folder + + validate_required_fields( + ["name", "collection_qualified_name", "parent_qualified_name"], + [name, collection_qualified_name, parent_qualified_name], + ) + if collection_qualified_name == parent_qualified_name: + parent = Collection.ref_by_qualified_name(collection_qualified_name) + else: + parent = Folder.ref_by_qualified_name(parent_qualified_name) + + query = Query( + attributes=Query.Attributes(qualified_name=qualified_name, name=name) + ) + query.parent = parent + query.collection_qualified_name = collection_qualified_name + query.parent_qualified_name = parent_qualified_name + return query + + def with_raw_query(self, schema_qualified_name: str, query: str): + _DEFAULT_VARIABLE_SCHEMA = dumps( + { + "customvariablesDateTimeFormat": { + "defaultDateFormat": "YYYY-MM-DD", + "defaultTimeFormat": "HH:mm", + }, + "customVariables": [], + } + ) + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + schema_qualified_name, "schema_qualified_name", 5 + ) + tokens = schema_qualified_name.split("/") + database_qn = f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + self.connection_name = connector_name + self.connection_qualified_name = connection_qn + self.default_database_qualified_name = database_qn + self.default_schema_qualified_name = schema_qualified_name + self.is_visual_query = False + self.raw_query_text = query + self.variables_schema_base64 = b64encode( + _DEFAULT_VARIABLE_SCHEMA.encode("utf-8") + ).decode("utf-8") diff --git a/pyatlan/generator/templates/methods/attribute/folder.jinja2 b/pyatlan/generator/templates/methods/attribute/folder.jinja2 index e34fbaf7..bed4fada 100644 --- a/pyatlan/generator/templates/methods/attribute/folder.jinja2 +++ b/pyatlan/generator/templates/methods/attribute/folder.jinja2 @@ -5,14 +5,17 @@ cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Folder.Attributes: from pyatlan.model.assets import Collection - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) + + if not (parent_folder_qualified_name or collection_qualified_name): + raise ValueError( + "Either 'collection_qualified_name' or 'parent_folder_qualified_name' to be specified." + ) if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" @@ -20,6 +23,12 @@ parent = Collection.ref_by_qualified_name(collection_qualified_name) else: + tokens = parent_folder_qualified_name.split("/") + if len(tokens) < 4: + raise ValueError("Invalid collection_qualified_name") + collection_qualified_name = ( + f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + ) qualified_name = f"{parent_folder_qualified_name}/{name}" parent_qn = parent_folder_qualified_name parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] diff --git a/pyatlan/generator/templates/methods/attribute/query.jinja2 b/pyatlan/generator/templates/methods/attribute/query.jinja2 index 01ab74a0..edface12 100644 --- a/pyatlan/generator/templates/methods/attribute/query.jinja2 +++ b/pyatlan/generator/templates/methods/attribute/query.jinja2 @@ -5,14 +5,17 @@ cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Query.Attributes: from pyatlan.model.assets import Collection, Folder - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) + + if not (parent_folder_qualified_name or collection_qualified_name): + raise ValueError( + "Either 'collection_qualified_name' or 'parent_folder_qualified_name' to be specified." + ) if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" @@ -20,6 +23,12 @@ parent = Collection.ref_by_qualified_name(collection_qualified_name) else: + tokens = parent_folder_qualified_name.split("/") + if len(tokens) < 4: + raise ValueError("Invalid collection_qualified_name") + collection_qualified_name = ( + f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + ) qualified_name = f"{parent_folder_qualified_name}/{name}" parent_qn = parent_folder_qualified_name parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] diff --git a/pyatlan/model/assets/core/folder.py b/pyatlan/model/assets/core/folder.py index 18e7e845..086c9f5f 100644 --- a/pyatlan/model/assets/core/folder.py +++ b/pyatlan/model/assets/core/folder.py @@ -32,7 +32,6 @@ def creator( cls, *, name: str, - collection_qualified_name: str, parent_folder_qualified_name: str, ) -> Folder: ... @@ -42,12 +41,10 @@ def creator( cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Folder: - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) return Folder( attributes=Folder.Attributes.creator( name=name, @@ -144,14 +141,17 @@ def creator( cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Folder.Attributes: from pyatlan.model.assets import Collection - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) + + if not (parent_folder_qualified_name or collection_qualified_name): + raise ValueError( + "Either 'collection_qualified_name' or 'parent_folder_qualified_name' to be specified." + ) if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" @@ -159,6 +159,12 @@ def creator( parent = Collection.ref_by_qualified_name(collection_qualified_name) else: + tokens = parent_folder_qualified_name.split("/") + if len(tokens) < 4: + raise ValueError("Invalid collection_qualified_name") + collection_qualified_name = ( + f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + ) qualified_name = f"{parent_folder_qualified_name}/{name}" parent_qn = parent_folder_qualified_name parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] diff --git a/pyatlan/model/assets/core/query.py b/pyatlan/model/assets/core/query.py index df137888..caa0dcfb 100644 --- a/pyatlan/model/assets/core/query.py +++ b/pyatlan/model/assets/core/query.py @@ -4,10 +4,13 @@ from __future__ import annotations +from base64 import b64encode +from json import dumps from typing import ClassVar, List, Optional, overload from pydantic.v1 import Field, validator +from pyatlan.model.enums import AtlanConnectorType from pyatlan.model.fields.atlan_fields import ( BooleanField, KeywordTextField, @@ -37,7 +40,6 @@ def creator( cls, *, name: str, - collection_qualified_name: str, parent_folder_qualified_name: str, ) -> Query: ... @@ -47,12 +49,10 @@ def creator( cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Query: - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) return Query( attributes=Query.Attributes.creator( name=name, @@ -61,6 +61,60 @@ def creator( ) ) + @classmethod + @init_guid + def updater( + cls, + *, + name: str, + qualified_name: str, + collection_qualified_name: str, + parent_qualified_name: str, + ) -> Query: + from pyatlan.model.assets import Collection, Folder + + validate_required_fields( + ["name", "collection_qualified_name", "parent_qualified_name"], + [name, collection_qualified_name, parent_qualified_name], + ) + if collection_qualified_name == parent_qualified_name: + parent = Collection.ref_by_qualified_name(collection_qualified_name) + else: + parent = Folder.ref_by_qualified_name(parent_qualified_name) + + query = Query( + attributes=Query.Attributes(qualified_name=qualified_name, name=name) + ) + query.parent = parent + query.collection_qualified_name = collection_qualified_name + query.parent_qualified_name = parent_qualified_name + return query + + def with_raw_query(self, schema_qualified_name: str, query: str): + _DEFAULT_VARIABLE_SCHEMA = dumps( + { + "customvariablesDateTimeFormat": { + "defaultDateFormat": "YYYY-MM-DD", + "defaultTimeFormat": "HH:mm", + }, + "customVariables": [], + } + ) + connection_qn, connector_name = AtlanConnectorType.get_connector_name( + schema_qualified_name, "schema_qualified_name", 5 + ) + tokens = schema_qualified_name.split("/") + database_qn = f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + self.connection_name = connector_name + self.connection_qualified_name = connection_qn + self.default_database_qualified_name = database_qn + self.default_schema_qualified_name = schema_qualified_name + self.is_visual_query = False + self.raw_query_text = query + self.variables_schema_base64 = b64encode( + _DEFAULT_VARIABLE_SCHEMA.encode("utf-8") + ).decode("utf-8") + type_name: str = Field(default="Query", allow_mutation=False) @validator("type_name") @@ -405,14 +459,17 @@ def creator( cls, *, name: str, - collection_qualified_name: str, + collection_qualified_name: Optional[str] = None, parent_folder_qualified_name: Optional[str] = None, ) -> Query.Attributes: from pyatlan.model.assets import Collection, Folder - validate_required_fields( - ["name", "collection_qualified_name"], [name, collection_qualified_name] - ) + validate_required_fields(["name"], [name]) + + if not (parent_folder_qualified_name or collection_qualified_name): + raise ValueError( + "Either 'collection_qualified_name' or 'parent_folder_qualified_name' to be specified." + ) if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" @@ -420,6 +477,12 @@ def creator( parent = Collection.ref_by_qualified_name(collection_qualified_name) else: + tokens = parent_folder_qualified_name.split("/") + if len(tokens) < 4: + raise ValueError("Invalid collection_qualified_name") + collection_qualified_name = ( + f"{tokens[0]}/{tokens[1]}/{tokens[2]}/{tokens[3]}" + ) qualified_name = f"{parent_folder_qualified_name}/{name}" parent_qn = parent_folder_qualified_name parent = Folder.ref_by_qualified_name(parent_folder_qualified_name) # type: ignore[assignment] From dc9b4a4f357bb01d8f5c9bc0db4a7b081cadc482 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 00:35:06 +0530 Subject: [PATCH 22/66] [test] Added Insights objects integration tests --- tests/integration/insights_test.py | 204 +++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 tests/integration/insights_test.py diff --git a/tests/integration/insights_test.py b/tests/integration/insights_test.py new file mode 100644 index 00000000..1112c8d0 --- /dev/null +++ b/tests/integration/insights_test.py @@ -0,0 +1,204 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 Atlan Pte. Ltd. +from typing import Generator + +import pytest + +from pyatlan.client.atlan import AtlanClient +from pyatlan.model.assets import Collection, Folder, Query, Schema +from pyatlan.model.enums import AtlanConnectorType, EntityStatus +from pyatlan.model.fluent_search import FluentSearch +from pyatlan.model.response import AssetMutationResponse +from tests.integration.client import TestId, delete_asset +from tests.integration.utils import block + +PREFIX = TestId.make_unique("INS") + +COLLECTION_NAME = PREFIX +FOLDER_NAME = PREFIX + "_folder" +SUB_FOLDER_NAME = FOLDER_NAME + "_sub" +QUERY_NAME = PREFIX + "_query" +RAW_QUERY = "SELECT * FROM DIM_CUSTOMERS;" +EXISTING_GROUP_NAME = "admins" +CONNECTION_NAME = "development" +DB_NAME = "analytics" +SCHEMA_NAME = "WIDE_WORLD_IMPORTERS" +USER_DESCRIPTION = "Automated testing of the Python SDK." + +response = block(AtlanClient(), AssetMutationResponse()) + + +@pytest.fixture(scope="module") +def collection(client: AtlanClient) -> Generator[Collection, None, None]: + collection = Collection.creator(client=client, name=COLLECTION_NAME) + collection.admin_groups = [EXISTING_GROUP_NAME] + response = client.asset.save(collection) + result = response.assets_created(asset_type=Collection)[0] + yield result + delete_asset(client, guid=result.guid, asset_type=Collection) + + +@pytest.fixture(scope="module") +def folder( + client: AtlanClient, collection: Collection +) -> Generator[Folder, None, None]: + folder = Folder.creator( + name=FOLDER_NAME, collection_qualified_name=collection.qualified_name + ) + response = client.asset.save(folder) + result = response.assets_created(asset_type=Folder)[0] + updated = response.assets_updated(asset_type=Collection)[0] + assert ( + updated + and updated.guid == collection.guid + and updated.qualified_name == collection.qualified_name + ) + yield result + delete_asset(client, guid=result.guid, asset_type=Folder) + + +@pytest.fixture(scope="module") +def sub_folder(client: AtlanClient, folder: Folder) -> Generator[Folder, None, None]: + sub = Folder.creator( + name=SUB_FOLDER_NAME, parent_folder_qualified_name=folder.qualified_name + ) + response = client.asset.save(sub) + result = response.assets_created(asset_type=Folder)[0] + updated = response.assets_updated(asset_type=Folder)[0] + assert ( + updated + and updated.guid == folder.guid + and updated.qualified_name == folder.qualified_name + ) + yield result + delete_asset(client, guid=result.guid, asset_type=Folder) + + +@pytest.fixture(scope="module") +def query(client: AtlanClient, folder: Folder) -> Generator[Query, None, None]: + connection = client.find_connections_by_name( + name=CONNECTION_NAME, connector_type=AtlanConnectorType.SNOWFLAKE + ) + assert connection and len(connection) == 1 + results = ( + FluentSearch() + .select() + .where(Schema.CONNECTION_QUALIFIED_NAME.eq(connection[0].qualified_name)) + .where(Schema.DATABASE_NAME.eq(DB_NAME)) + .where(Schema.NAME.eq(SCHEMA_NAME)) + .execute(client=client) + ) + assert results and len(results.current_page()) == 1 + schema = results.current_page()[0] + assert schema + to_create = Query.creator( + name=QUERY_NAME, parent_folder_qualified_name=folder.qualified_name + ) + to_create.with_raw_query( + schema_qualified_name=schema.qualified_name, query=RAW_QUERY + ) + response = client.asset.save(to_create) + result = response.assets_created(asset_type=Query)[0] + updated = response.assets_updated(asset_type=Folder)[0] + assert ( + updated + and updated.guid == folder.guid + and updated.qualified_name == folder.qualified_name + ) + yield result + delete_asset(client, guid=result.guid, asset_type=Folder) + + +def test_create_collection(collection): + assert collection + assert collection.name == COLLECTION_NAME + assert collection.guid and collection.qualified_name + + +def test_create_folder(folder, collection): + assert folder + assert folder.name == FOLDER_NAME + assert folder.guid and folder.qualified_name + assert folder.collection_qualified_name == collection.qualified_name + assert folder.parent_qualified_name == collection.qualified_name + + +def test_create_sub_folder(sub_folder: Folder, folder: Folder, collection: Collection): + assert sub_folder + assert sub_folder.name == SUB_FOLDER_NAME + assert sub_folder.guid and sub_folder.qualified_name + assert sub_folder.collection_qualified_name == collection.qualified_name + assert sub_folder.parent_qualified_name == folder.qualified_name + + +def test_create_query( + client: AtlanClient, query: Query, folder: Folder, collection: Collection +): + assert query + assert query.name == QUERY_NAME + assert query.guid and query.qualified_name + assert query.collection_qualified_name == collection.qualified_name + assert query.parent_qualified_name == folder.qualified_name + + +def test_update_query( + client: AtlanClient, + collection: Collection, + folder: Folder, + query: Query, +): + query = query.updater( + name=query.name, + qualified_name=query.qualified_name, + collection_qualified_name=collection.qualified_name, + parent_qualified_name=folder.qualified_name, + ) + query.user_description = USER_DESCRIPTION + response = client.asset.save(query) + updated = response.assets_updated(asset_type=Query)[0] + assert updated and updated.qualified_name == query.qualified_name + + +@pytest.mark.order(after="test_update_query") +def test_retrieve_query( + client: AtlanClient, + query: Query, +): + retrieved = client.asset.get_by_guid(query.guid, asset_type=Query) + assert retrieved + assert not retrieved.is_incomplete + assert retrieved.guid == query.guid + assert retrieved.qualified_name == query.qualified_name + assert retrieved.name == query.name + assert retrieved.user_description == USER_DESCRIPTION + + +@pytest.mark.order(after="test_retrieve_query") +def test_delete_query( + client: AtlanClient, + query: Query, +): + response = client.asset.delete_by_guid(guid=query.guid) + assert response + assert not response.assets_created(asset_type=Query) + assert not response.assets_updated(asset_type=Query) + deleted = response.assets_deleted(asset_type=Query) + + assert deleted + assert len(deleted) == 1 + assert deleted[0].guid == query.guid + assert deleted[0].delete_handler == "SOFT" + assert deleted[0].status == EntityStatus.DELETED + assert deleted[0].qualified_name == query.qualified_name + + +@pytest.mark.order(after="test_delete_query") +def test_read_deleted_query( + client: AtlanClient, + query: query, +): + deleted = client.asset.get_by_guid(query.guid, asset_type=Query) + assert deleted + assert deleted.status == EntityStatus.DELETED + assert deleted.guid == query.guid + assert deleted.qualified_name == query.qualified_name From fe3bb898611f2bce7d911e2259f9cb63c969d661 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 00:39:03 +0530 Subject: [PATCH 23/66] [qa/fix] Fixed mypy violations --- pyatlan/generator/templates/methods/asset/query.jinja2 | 2 +- pyatlan/generator/templates/methods/attribute/folder.jinja2 | 4 +++- pyatlan/generator/templates/methods/attribute/query.jinja2 | 4 +++- pyatlan/model/assets/core/folder.py | 4 +++- pyatlan/model/assets/core/query.py | 6 ++++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pyatlan/generator/templates/methods/asset/query.jinja2 b/pyatlan/generator/templates/methods/asset/query.jinja2 index 7d206909..b3f8086d 100644 --- a/pyatlan/generator/templates/methods/asset/query.jinja2 +++ b/pyatlan/generator/templates/methods/asset/query.jinja2 @@ -54,7 +54,7 @@ if collection_qualified_name == parent_qualified_name: parent = Collection.ref_by_qualified_name(collection_qualified_name) else: - parent = Folder.ref_by_qualified_name(parent_qualified_name) + parent = Folder.ref_by_qualified_name(parent_qualified_name) # type: ignore[assignment] query = Query( attributes=Query.Attributes(qualified_name=qualified_name, name=name) diff --git a/pyatlan/generator/templates/methods/attribute/folder.jinja2 b/pyatlan/generator/templates/methods/attribute/folder.jinja2 index bed4fada..dcc04c34 100644 --- a/pyatlan/generator/templates/methods/attribute/folder.jinja2 +++ b/pyatlan/generator/templates/methods/attribute/folder.jinja2 @@ -20,7 +20,9 @@ if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" parent_qn = collection_qualified_name - parent = Collection.ref_by_qualified_name(collection_qualified_name) + parent = Collection.ref_by_qualified_name( + collection_qualified_name or "" + ) else: tokens = parent_folder_qualified_name.split("/") diff --git a/pyatlan/generator/templates/methods/attribute/query.jinja2 b/pyatlan/generator/templates/methods/attribute/query.jinja2 index edface12..5280dc5a 100644 --- a/pyatlan/generator/templates/methods/attribute/query.jinja2 +++ b/pyatlan/generator/templates/methods/attribute/query.jinja2 @@ -20,7 +20,9 @@ if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" parent_qn = collection_qualified_name - parent = Collection.ref_by_qualified_name(collection_qualified_name) + parent = Collection.ref_by_qualified_name( + collection_qualified_name or "" + ) else: tokens = parent_folder_qualified_name.split("/") diff --git a/pyatlan/model/assets/core/folder.py b/pyatlan/model/assets/core/folder.py index 086c9f5f..e06aa147 100644 --- a/pyatlan/model/assets/core/folder.py +++ b/pyatlan/model/assets/core/folder.py @@ -156,7 +156,9 @@ def creator( if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" parent_qn = collection_qualified_name - parent = Collection.ref_by_qualified_name(collection_qualified_name) + parent = Collection.ref_by_qualified_name( + collection_qualified_name or "" + ) else: tokens = parent_folder_qualified_name.split("/") diff --git a/pyatlan/model/assets/core/query.py b/pyatlan/model/assets/core/query.py index caa0dcfb..1f4bd520 100644 --- a/pyatlan/model/assets/core/query.py +++ b/pyatlan/model/assets/core/query.py @@ -80,7 +80,7 @@ def updater( if collection_qualified_name == parent_qualified_name: parent = Collection.ref_by_qualified_name(collection_qualified_name) else: - parent = Folder.ref_by_qualified_name(parent_qualified_name) + parent = Folder.ref_by_qualified_name(parent_qualified_name) # type: ignore[assignment] query = Query( attributes=Query.Attributes(qualified_name=qualified_name, name=name) @@ -474,7 +474,9 @@ def creator( if not parent_folder_qualified_name: qualified_name = f"{collection_qualified_name}/{name}" parent_qn = collection_qualified_name - parent = Collection.ref_by_qualified_name(collection_qualified_name) + parent = Collection.ref_by_qualified_name( + collection_qualified_name or "" + ) else: tokens = parent_folder_qualified_name.split("/") From c021c1e83228283a2dbb8350201590c6d42ae5b9 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 00:43:26 +0530 Subject: [PATCH 24/66] [qa/fix] Fixed integration tests mypy violations --- tests/integration/insights_test.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/integration/insights_test.py b/tests/integration/insights_test.py index 1112c8d0..7847e66e 100644 --- a/tests/integration/insights_test.py +++ b/tests/integration/insights_test.py @@ -42,6 +42,7 @@ def collection(client: AtlanClient) -> Generator[Collection, None, None]: def folder( client: AtlanClient, collection: Collection ) -> Generator[Folder, None, None]: + assert collection and collection.qualified_name folder = Folder.creator( name=FOLDER_NAME, collection_qualified_name=collection.qualified_name ) @@ -59,6 +60,7 @@ def folder( @pytest.fixture(scope="module") def sub_folder(client: AtlanClient, folder: Folder) -> Generator[Folder, None, None]: + assert folder and folder.qualified_name sub = Folder.creator( name=SUB_FOLDER_NAME, parent_folder_qualified_name=folder.qualified_name ) @@ -79,7 +81,7 @@ def query(client: AtlanClient, folder: Folder) -> Generator[Query, None, None]: connection = client.find_connections_by_name( name=CONNECTION_NAME, connector_type=AtlanConnectorType.SNOWFLAKE ) - assert connection and len(connection) == 1 + assert connection and len(connection) == 1 and connection[0].qualified_name results = ( FluentSearch() .select() @@ -90,7 +92,8 @@ def query(client: AtlanClient, folder: Folder) -> Generator[Query, None, None]: ) assert results and len(results.current_page()) == 1 schema = results.current_page()[0] - assert schema + assert schema and schema.qualified_name + assert folder and folder.qualified_name to_create = Query.creator( name=QUERY_NAME, parent_folder_qualified_name=folder.qualified_name ) @@ -195,9 +198,9 @@ def test_delete_query( @pytest.mark.order(after="test_delete_query") def test_read_deleted_query( client: AtlanClient, - query: query, + query: Query, ): - deleted = client.asset.get_by_guid(query.guid, asset_type=Query) + deleted = client.asset.get_by_guid(guid=query.guid, asset_type=Query) assert deleted assert deleted.status == EntityStatus.DELETED assert deleted.guid == query.guid From f1a9b28e6a5a490fbbf07a1f3862b07a2f2a9484 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Mon, 30 Dec 2024 09:48:49 +0300 Subject: [PATCH 25/66] Add logic for open telementry logging. --- pyatlan/pkg/utils.py | 91 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index 4f8b16a2..b8f34e41 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -3,7 +3,7 @@ import json import logging import os -from typing import Dict, List +from typing import Any, Dict, List, Mapping, Optional, Sequence, Union from pydantic.v1 import parse_obj_as, parse_raw_as @@ -12,6 +12,56 @@ LOGGER = logging.getLogger(__name__) +# Try to import OpenTelemetry libraries +try: + from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( + OTLPLogExporter, # type:ignore + ) + from opentelemetry.sdk._logs import ( # type:ignore + LogData, + LoggerProvider, + LoggingHandler, + ) + from opentelemetry.sdk._logs._internal.export import ( + BatchLogRecordProcessor, # type:ignore + ) + from opentelemetry.sdk.resources import Resource # type:ignore + + class CustomBatchLogRecordProcessor(BatchLogRecordProcessor): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def emit(self, log_data: LogData) -> None: + if not self._is_valid_type(log_data.log_record.body): + log_data.log_record.body = str(log_data.log_record.body) + super().emit(log_data) + + def _is_valid_type(self, value: Any) -> bool: + # see https://github.com/open-telemetry/opentelemetry-python/blob/c883f6cc1243ab7e0e5bc177169f25cdf0aac29f/ + # exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal + # /__init__.py#L69 + # for valid encode types + if isinstance(value, bool): + return True + if isinstance(value, str): + return True + if isinstance(value, int): + return True + if isinstance(value, float): + return True + if isinstance(value, Sequence): + return all(self._is_valid_type(v) for v in value) + elif isinstance(value, Mapping): + return all( + self._is_valid_type(k) & self._is_valid_type(v) + for k, v in value.items() + ) + return False + + OTEL_IMPORTS_AVAILABLE = True +except ImportError: + OTEL_IMPORTS_AVAILABLE = False + def get_client(impersonate_user_id: str) -> AtlanClient: """ @@ -117,3 +167,42 @@ def validate_connector_and_connection(v): from pyatlan.pkg.models import ConnectorAndConnection return parse_raw_as(ConnectorAndConnection, v) + + +def has_handler(logger: logging.Logger, handler_class) -> bool: + c: Optional[logging.Logger] = logger + while c: + for hdlr in c.handlers: + if isinstance(hdlr, handler_class): + return True + c = c.parent if c.propagate else None + return False + + +def add_otel_handler( + logger: logging.Logger, level: Union[int, str], resource: dict +) -> None: + """ + Adds an OpenTelemetry handler to the logger if not already present. + + Args: + logger (logging.Logger): The logger to which the handler will be added. + level (int | str): The logging level. + resource (dict): A dictionary of resource attributes to be associated with the logger. + """ + if OTEL_IMPORTS_AVAILABLE and not has_handler(logger, LoggingHandler): + workflow_node_name = os.getenv("OTEL_WF_NODE_NAME", "") + if workflow_node_name: + resource["k8s.workflow.node.name"] = workflow_node_name + logger_provider = LoggerProvider(Resource.create(resource)) + otel_log_exporter = OTLPLogExporter( + endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT"), insecure=True + ) + logger_provider.add_log_record_processor( + CustomBatchLogRecordProcessor(otel_log_exporter) + ) + + otel_handler = LoggingHandler(level=level, logger_provider=logger_provider) + otel_handler.setLevel(level) + logger.addHandler(otel_handler) + logger.info("OpenTelemetry handler added to the logger.") From 76fc8d1540bea3597371bba260fdb8828566d001 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Mon, 30 Dec 2024 12:18:28 +0300 Subject: [PATCH 26/66] Fix broken test --- pyatlan/pkg/utils.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index b8f34e41..31860575 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -14,16 +14,16 @@ # Try to import OpenTelemetry libraries try: - from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( - OTLPLogExporter, # type:ignore + from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( # type:ignore + OTLPLogExporter, ) from opentelemetry.sdk._logs import ( # type:ignore LogData, LoggerProvider, LoggingHandler, ) - from opentelemetry.sdk._logs._internal.export import ( - BatchLogRecordProcessor, # type:ignore + from opentelemetry.sdk._logs._internal.export import ( # type:ignore + BatchLogRecordProcessor, ) from opentelemetry.sdk.resources import Resource # type:ignore @@ -170,6 +170,18 @@ def validate_connector_and_connection(v): def has_handler(logger: logging.Logger, handler_class) -> bool: + """ + Checks if a logger or its ancestor has a handler of a specific class. The function + iterates through the logger's handlers and optionally ascends the logger hierarchy, + checking each logger's handlers for an instance of the specified handler class. + + Args: + logger (logging.Logger): The logger to inspect for the handler. + handler_class: The class of the handler to look for. + + Returns: + bool: True if the handler of the specified class is found, False otherwise. + """ c: Optional[logging.Logger] = logger while c: for hdlr in c.handlers: From 6706cae3fa3bf545ed53be8e4b1d98b5593225a5 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 09:01:14 +0300 Subject: [PATCH 27/66] Improve code quality --- pyatlan/pkg/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index 31860575..7cbe662a 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -203,8 +203,7 @@ def add_otel_handler( resource (dict): A dictionary of resource attributes to be associated with the logger. """ if OTEL_IMPORTS_AVAILABLE and not has_handler(logger, LoggingHandler): - workflow_node_name = os.getenv("OTEL_WF_NODE_NAME", "") - if workflow_node_name: + if workflow_node_name := os.getenv("OTEL_WF_NODE_NAME", ""): resource["k8s.workflow.node.name"] = workflow_node_name logger_provider = LoggerProvider(Resource.create(resource)) otel_log_exporter = OTLPLogExporter( From 7f64dfcdf66ef6cb24f601b7102e05ea5db97c6c Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 12:47:06 +0300 Subject: [PATCH 28/66] Add formatter to otel handler. --- pyatlan/pkg/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index 7cbe662a..96c8d057 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -215,5 +215,9 @@ def add_otel_handler( otel_handler = LoggingHandler(level=level, logger_provider=logger_provider) otel_handler.setLevel(level) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) + otel_handler.setFormatter(formatter) logger.addHandler(otel_handler) logger.info("OpenTelemetry handler added to the logger.") From bdeaf845639374be418c5b0768793a4b9072edb7 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 12:54:04 +0300 Subject: [PATCH 29/66] Add formatter to otel handler. --- pyatlan/pkg/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index 96c8d057..c9e7484a 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -220,4 +220,4 @@ def add_otel_handler( ) otel_handler.setFormatter(formatter) logger.addHandler(otel_handler) - logger.info("OpenTelemetry handler added to the logger.") + logger.info("OpenTelemetry handler with formatter added to the logger.") From c99c61c898ee7f284e71fac62f8b86b393f2592d Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 15:11:51 +0300 Subject: [PATCH 30/66] Change add_otel_handler to return Optional[logging.Handler]. --- pyatlan/pkg/utils.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/pyatlan/pkg/utils.py b/pyatlan/pkg/utils.py index c9e7484a..027be6e2 100644 --- a/pyatlan/pkg/utils.py +++ b/pyatlan/pkg/utils.py @@ -193,14 +193,28 @@ def has_handler(logger: logging.Logger, handler_class) -> bool: def add_otel_handler( logger: logging.Logger, level: Union[int, str], resource: dict -) -> None: - """ - Adds an OpenTelemetry handler to the logger if not already present. +) -> Optional[logging.Handler]: + """ + Adds an OpenTelemetry logging handler to the provided logger if the necessary + OpenTelemetry imports are available and the handler is not already present. + This function uses the provided logging level and resource configuration for + setting up the OpenTelemetry handler. The handler is set up with a custom + formatter for log messages. This function also makes use of workflow-specific + environment variables to enrich the resource data with workflow node + information if available. + + Parameters: + logger (logging.Logger): The logger instance to which the OpenTelemetry + handler will be added. + level (Union[int, str]): The logging level to be set for the OpenTelemetry + handler, such as logging.INFO or logging.DEBUG. + resource (dict): A dictionary representing the OpenTelemetry resource + configuration. Additional resource attributes may be dynamically added + inside the function. - Args: - logger (logging.Logger): The logger to which the handler will be added. - level (int | str): The logging level. - resource (dict): A dictionary of resource attributes to be associated with the logger. + Returns: + Optional[logging.Logger]: The created OpenTelemetry handler if successfully + added; otherwise, None. """ if OTEL_IMPORTS_AVAILABLE and not has_handler(logger, LoggingHandler): if workflow_node_name := os.getenv("OTEL_WF_NODE_NAME", ""): @@ -221,3 +235,5 @@ def add_otel_handler( otel_handler.setFormatter(formatter) logger.addHandler(otel_handler) logger.info("OpenTelemetry handler with formatter added to the logger.") + return otel_handler + return None From c851dff0cb7a4b42edcbabf9c47f697e32d1d8e1 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 15:40:41 +0300 Subject: [PATCH 31/66] Add additional redaction of logs --- pyatlan/utils.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pyatlan/utils.py b/pyatlan/utils.py index 3411b688..8ab206bb 100644 --- a/pyatlan/utils.py +++ b/pyatlan/utils.py @@ -337,12 +337,11 @@ class AuthorizationFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: if record.args and hasattr(record.args, "__iter__"): for arg in record.args: - if ( - isinstance(arg, dict) - and "headers" in arg - and "authorization" in arg["headers"] - ): - arg["headers"]["authorization"] = "***REDACTED***" + if isinstance(arg, dict): + if "headers" in arg and "authorization" in arg["headers"]: + arg["headers"]["authorization"] = "***REDACTED***" + elif "access_token" in arg: + arg["access_token"] = "***REDACTED***" # noqa: S105 return True From 3b0d50faa5db451ac0921c993bd0a64faf5852e5 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 16:04:40 +0300 Subject: [PATCH 32/66] Modified logging --- pyatlan/client/atlan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyatlan/client/atlan.py b/pyatlan/client/atlan.py index 53ba4964..99a83a31 100644 --- a/pyatlan/client/atlan.py +++ b/pyatlan/client/atlan.py @@ -403,7 +403,7 @@ def _call_api_internal( response_ = response.text else: response_ = events if events else response.json() - LOGGER.debug(response_) + LOGGER.debug("response: %s", response_) return response_ except ( requests.exceptions.JSONDecodeError, From f30301686ab4fb05a44a4b03311074478a4bbe01 Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 17:05:34 +0300 Subject: [PATCH 33/66] Change log redaction logic. --- pyatlan/utils.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pyatlan/utils.py b/pyatlan/utils.py index 8ab206bb..0081fba1 100644 --- a/pyatlan/utils.py +++ b/pyatlan/utils.py @@ -335,13 +335,16 @@ class AuthorizationFilter(logging.Filter): """ def filter(self, record: logging.LogRecord) -> bool: - if record.args and hasattr(record.args, "__iter__"): + if isinstance(record.args, dict) and "access_token" in record.args: + record.args["access_token"] = "***REDACTED***" # noqa: S105 + elif record.args and hasattr(record.args, "__iter__"): for arg in record.args: - if isinstance(arg, dict): - if "headers" in arg and "authorization" in arg["headers"]: - arg["headers"]["authorization"] = "***REDACTED***" - elif "access_token" in arg: - arg["access_token"] = "***REDACTED***" # noqa: S105 + if ( + isinstance(arg, dict) + and "headers" in arg + and "authorization" in arg["headers"] + ): + arg["headers"]["authorization"] = "***REDACTED***" return True From c6687c77810e0ea831c586589040d681b6d56c3e Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Tue, 31 Dec 2024 17:19:47 +0300 Subject: [PATCH 34/66] Change log redaction logic. --- pyatlan/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyatlan/utils.py b/pyatlan/utils.py index 0081fba1..a2217bb1 100644 --- a/pyatlan/utils.py +++ b/pyatlan/utils.py @@ -336,6 +336,7 @@ class AuthorizationFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: if isinstance(record.args, dict) and "access_token" in record.args: + record.args = record.args.copy() record.args["access_token"] = "***REDACTED***" # noqa: S105 elif record.args and hasattr(record.args, "__iter__"): for arg in record.args: From 6d6fed54d98954449cd13fd25e4799b46a7454ce Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 19:37:03 +0530 Subject: [PATCH 35/66] [test/fix] Removed hardcoded column qualifiedName in `test_search_source_specific_custom_attributes` --- tests/integration/test_index_search.py | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/integration/test_index_search.py b/tests/integration/test_index_search.py index b49f1cf0..4f17b35d 100644 --- a/tests/integration/test_index_search.py +++ b/tests/integration/test_index_search.py @@ -37,10 +37,10 @@ NOW_AS_YYYY_MM_DD = datetime.today().strftime("%Y-%m-%d") EXISTING_TAG = "Issue" EXISTING_SOURCE_SYNCED_TAG = "Confidential" -COLUMN_WITH_CUSTOM_ATTRIBUTES = ( - "default/snowflake/1733440936/ANALYTICS" - "/WIDE_WORLD_IMPORTERS/STG_STATE_PROVINCES/LATEST_RECORDED_POPULATION" -) +DB_NAME = "ANALYTICS" +TABLE_NAME = "STG_STATE_PROVINCES" +COLUMN_NAME = "LATEST_RECORDED_POPULATION" +SCHEMA_NAME = "WIDE_WORLD_IMPORTERS" VALUES_FOR_TERM_QUERIES = { "with_categories": "VBsYc9dUoEcAtDxZmjby6@mweSfpXBwfYWedQTvA3Gi", @@ -94,6 +94,18 @@ } +@pytest.fixture(scope="module") +def snowflake_conn(client: AtlanClient): + return client.asset.find_connections_by_name( + "development", AtlanConnectorType.SNOWFLAKE + )[0] + + +@pytest.fixture(scope="module") +def snowflake_column_qn(snowflake_conn): + return f"{snowflake_conn.qualified_name}/{DB_NAME}/{SCHEMA_NAME}/{TABLE_NAME}/{COLUMN_NAME}" + + @dataclass() class AssetTracker: missing_types: Set[str] = field(default_factory=set) @@ -249,12 +261,13 @@ def test_source_tag_assign_with_value(client: AtlanClient, table: Table): _assert_source_tag(tables, EXISTING_SOURCE_SYNCED_TAG, "Not Restricted") -def test_search_source_specific_custom_attributes(client: AtlanClient): +def test_search_source_specific_custom_attributes( + client: AtlanClient, snowflake_column_qn: str +): # Test with get_by_qualified_name() - column_qn = COLUMN_WITH_CUSTOM_ATTRIBUTES asset = client.asset.get_by_qualified_name( asset_type=Column, - qualified_name=column_qn, + qualified_name=snowflake_column_qn, min_ext_info=True, ignore_relationships=True, ) @@ -264,7 +277,7 @@ def test_search_source_specific_custom_attributes(client: AtlanClient): results = ( FluentSearch() .where(CompoundQuery.active_assets()) - .where(Column.QUALIFIED_NAME.eq(column_qn)) + .where(Column.QUALIFIED_NAME.eq(snowflake_column_qn)) .include_on_results(Column.CUSTOM_ATTRIBUTES) .execute(client=client) ) From be461f3dec1c2f8df74ed81bdea6c6e0973207d7 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 21:31:19 +0530 Subject: [PATCH 36/66] [test/fix] Fixed test fixtures for `anaplan_asset_test` --- tests/integration/anaplan_asset_test.py | 85 +++++++++++++------------ 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/tests/integration/anaplan_asset_test.py b/tests/integration/anaplan_asset_test.py index 7a61044f..8fc07f27 100644 --- a/tests/integration/anaplan_asset_test.py +++ b/tests/integration/anaplan_asset_test.py @@ -118,11 +118,11 @@ def test_anaplan_app( @pytest.fixture(scope="module") def anaplan_page( - client: AtlanClient, app: AnaplanApp + client: AtlanClient, anaplan_app: AnaplanApp ) -> Generator[AnaplanPage, None, None]: - assert app.qualified_name + assert anaplan_app.qualified_name to_create = AnaplanPage.creator( - name=ANAPLAN_PAGE_NAME, app_qualified_name=app.qualified_name + name=ANAPLAN_PAGE_NAME, app_qualified_name=anaplan_app.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanPage)[0] @@ -145,13 +145,13 @@ def test_anaplan_page( @pytest.fixture(scope="module") def anaplan_page_overload( - client: AtlanClient, connection: Connection, app: AnaplanApp + client: AtlanClient, connection: Connection, anaplan_app: AnaplanApp ) -> Generator[AnaplanPage, None, None]: assert connection.qualified_name - assert app.qualified_name + assert anaplan_app.qualified_name to_create = AnaplanPage.creator( name=ANAPLAN_PAGE_NAME_OVERLOAD, - app_qualified_name=app.qualified_name, + app_qualified_name=anaplan_app.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -176,11 +176,12 @@ def test_overload_anaplan_page( @pytest.fixture(scope="module") def anaplan_model( - client: AtlanClient, workspace: AnaplanWorkspace + client: AtlanClient, anaplan_workspace: AnaplanWorkspace ) -> Generator[AnaplanModel, None, None]: - assert workspace.qualified_name + assert anaplan_workspace.qualified_name to_create = AnaplanModel.creator( - name=ANAPLAN_MODEL_NAME, workspace_qualified_name=workspace.qualified_name + name=ANAPLAN_MODEL_NAME, + workspace_qualified_name=anaplan_workspace.qualified_name, ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanModel)[0] @@ -206,13 +207,13 @@ def test_anaplan_model( @pytest.fixture(scope="module") def anaplan_model_overload( - client: AtlanClient, connection: Connection, workspace: AnaplanWorkspace + client: AtlanClient, connection: Connection, anaplan_workspace: AnaplanWorkspace ) -> Generator[AnaplanModel, None, None]: assert connection.qualified_name - assert workspace.qualified_name + assert anaplan_workspace.qualified_name to_create = AnaplanModel.creator( name=ANAPLAN_MODEL_NAME_OVERLOAD, - workspace_qualified_name=workspace.qualified_name, + workspace_qualified_name=anaplan_workspace.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -239,11 +240,11 @@ def test_overload_anaplan_model( @pytest.fixture(scope="module") def anaplan_module( - client: AtlanClient, model: AnaplanModel + client: AtlanClient, anaplan_model: AnaplanModel ) -> Generator[AnaplanModule, None, None]: - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanModule.creator( - name=ANAPLAN_MODULE_NAME, model_qualified_name=model.qualified_name + name=ANAPLAN_MODULE_NAME, model_qualified_name=anaplan_model.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanModule)[0] @@ -267,13 +268,13 @@ def test_anaplan_module( @pytest.fixture(scope="module") def anaplan_module_overload( - client: AtlanClient, connection: Connection, model: AnaplanModel + client: AtlanClient, connection: Connection, anaplan_model: AnaplanModel ) -> Generator[AnaplanModule, None, None]: assert connection.qualified_name - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanModule.creator( name=ANAPLAN_MODULE_NAME_OVERLOAD, - model_qualified_name=model.qualified_name, + model_qualified_name=anaplan_model.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -300,11 +301,11 @@ def test_overload_anaplan_module( @pytest.fixture(scope="module") def anaplan_list( - client: AtlanClient, model: AnaplanModel + client: AtlanClient, anaplan_model: AnaplanModel ) -> Generator[AnaplanList, None, None]: - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanList.creator( - name=ANAPLAN_LIST_NAME, model_qualified_name=model.qualified_name + name=ANAPLAN_LIST_NAME, model_qualified_name=anaplan_model.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanList)[0] @@ -328,13 +329,13 @@ def test_anaplan_list( @pytest.fixture(scope="module") def anaplan_list_overload( - client: AtlanClient, connection: Connection, model: AnaplanModel + client: AtlanClient, connection: Connection, anaplan_model: AnaplanModel ) -> Generator[AnaplanList, None, None]: assert connection.qualified_name - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanList.creator( name=ANAPLAN_LIST_NAME_OVERLOAD, - model_qualified_name=model.qualified_name, + model_qualified_name=anaplan_model.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -359,11 +360,11 @@ def test_overload_anaplan_list( @pytest.fixture(scope="module") def anaplan_dimension( - client: AtlanClient, model: AnaplanModel + client: AtlanClient, anaplan_model: AnaplanModel ) -> Generator[AnaplanDimension, None, None]: - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanDimension.creator( - name=ANAPLAN_DIMENSION_NAME, model_qualified_name=model.qualified_name + name=ANAPLAN_DIMENSION_NAME, model_qualified_name=anaplan_model.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanDimension)[0] @@ -389,13 +390,13 @@ def test_anaplan_dimension( @pytest.fixture(scope="module") def anaplan_dimension_overload( - client: AtlanClient, connection: Connection, model: AnaplanModel + client: AtlanClient, connection: Connection, anaplan_model: AnaplanModel ) -> Generator[AnaplanDimension, None, None]: assert connection.qualified_name - assert model.qualified_name + assert anaplan_model.qualified_name to_create = AnaplanDimension.creator( name=ANAPLAN_DIMENSION_NAME_OVERLOAD, - model_qualified_name=model.qualified_name, + model_qualified_name=anaplan_model.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -422,11 +423,11 @@ def test_overload_anaplan_dimension( @pytest.fixture(scope="module") def anaplan_lineitem( - client: AtlanClient, module: AnaplanModule + client: AtlanClient, anaplan_module: AnaplanModule ) -> Generator[AnaplanLineItem, None, None]: - assert module.qualified_name + assert anaplan_module.qualified_name to_create = AnaplanLineItem.creator( - name=ANAPLAN_LINEITEM_NAME, module_qualified_name=module.qualified_name + name=ANAPLAN_LINEITEM_NAME, module_qualified_name=anaplan_module.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanLineItem)[0] @@ -452,13 +453,13 @@ def test_anaplan_lineitem( @pytest.fixture(scope="module") def anaplan_lineitem_overload( - client: AtlanClient, connection: Connection, module: AnaplanModule + client: AtlanClient, connection: Connection, anaplan_module: AnaplanModule ) -> Generator[AnaplanLineItem, None, None]: assert connection.qualified_name - assert module.qualified_name + assert anaplan_module.qualified_name to_create = AnaplanLineItem.creator( name=ANAPLAN_LINEITEM_NAME_OVERLOAD, - module_qualified_name=module.qualified_name, + module_qualified_name=anaplan_module.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) @@ -485,11 +486,11 @@ def test_overload_anaplan_lineitem( @pytest.fixture(scope="module") def anaplan_view( - client: AtlanClient, module: AnaplanModule + client: AtlanClient, anaplan_module: AnaplanModule ) -> Generator[AnaplanView, None, None]: - assert module.qualified_name + assert anaplan_module.qualified_name to_create = AnaplanView.creator( - name=ANAPLAN_VIEW_NAME, module_qualified_name=module.qualified_name + name=ANAPLAN_VIEW_NAME, module_qualified_name=anaplan_module.qualified_name ) response = client.asset.save(to_create) result = response.assets_created(asset_type=AnaplanView)[0] @@ -513,13 +514,13 @@ def test_anaplan_view( @pytest.fixture(scope="module") def anaplan_view_overload( - client: AtlanClient, connection: Connection, module: AnaplanModule + client: AtlanClient, connection: Connection, anaplan_module: AnaplanModule ) -> Generator[AnaplanView, None, None]: assert connection.qualified_name - assert module.qualified_name + assert anaplan_module.qualified_name to_create = AnaplanView.creator( name=ANAPLAN_VIEW_NAME_OVERLOAD, - module_qualified_name=module.qualified_name, + module_qualified_name=anaplan_module.qualified_name, connection_qualified_name=connection.qualified_name, ) response = client.asset.save(to_create) From 636ad96fbf527bd386e6072586885998ba71db05 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 21:57:37 +0530 Subject: [PATCH 37/66] Bump to release `3.1.2` --- HISTORY.md | 24 ++++++++++++++++++++++++ pyatlan/version.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index fe90a427..1e1ba31e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,27 @@ +## 3.1.2 (December 31, 2024) + +### New features + +- Enabled the use of the `Retry-After` header for handling rate-limit retries. +- Added support for [OpenTelemetry](https://opentelemetry.io) logging in custom packages. +- Added `creator()` methods for Insights assets (`Collection`, `Folder`, `Query`). +- Added support for the following new connector types: + - ANAPLAN + - AWS_ECS + - AWS_BATCH + - AWS_LAMBDA + - AWS_SAGEMAKER + - DATAVERSE + +### QOL improvements + +- Generated the latest typedef models. +- Fixed pagination assertions in `AuditSearch` unit tests and integration tests. + +### Bug fixes + +- Fixed a `ValidationError` caused by the private field (`_user_id`) in the `AtlanClient` constructor. + ## 3.1.1 (December 26, 2024) ### Bug fixes diff --git a/pyatlan/version.txt b/pyatlan/version.txt index 94ff29cc..ef538c28 100644 --- a/pyatlan/version.txt +++ b/pyatlan/version.txt @@ -1 +1 @@ -3.1.1 +3.1.2 From 082b4ef7229040b8496a7b565c85a9bd365315fd Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Tue, 31 Dec 2024 22:03:34 +0530 Subject: [PATCH 38/66] [deps] Upgraded `jinja2` from `3.1.5` to `3.1.5` to address a security vulnerability --- .conda-envs/meta.yaml | 4 ++-- HISTORY.md | 5 +---- docs/requirements.txt | 2 +- requirements.txt | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.conda-envs/meta.yaml b/.conda-envs/meta.yaml index 4fa28710..9d867040 100644 --- a/.conda-envs/meta.yaml +++ b/.conda-envs/meta.yaml @@ -11,7 +11,7 @@ build: requirements: host: - - jinja2 ==3.1.4 + - jinja2 ==3.1.5 - lazy_loader~=0.4 - pip - pydantic >=2.0.0,<3.0.0 @@ -20,7 +20,7 @@ requirements: - tenacity ==8.2.3 - urllib3 >=1.26.0,<3 run: - - jinja2 ==3.1.4 + - jinja2 ==3.1.5 - lazy_loader~=0.4 - pydantic >=2.0.0,<3.0.0 - python diff --git a/HISTORY.md b/HISTORY.md index 1e1ba31e..693cc90c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -16,12 +16,9 @@ ### QOL improvements - Generated the latest typedef models. +- Upgraded `jinja2` from `3.1.4` to `3.1.5` to address a security vulnerability. - Fixed pagination assertions in `AuditSearch` unit tests and integration tests. -### Bug fixes - -- Fixed a `ValidationError` caused by the private field (`_user_id`) in the `AtlanClient` constructor. - ## 3.1.1 (December 26, 2024) ### Bug fixes diff --git a/docs/requirements.txt b/docs/requirements.txt index fcca8ff9..8e92c024 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,6 +2,6 @@ sphinx~=7.2.6 furo~=2024.1.29 requests>=2.24 pydantic~=2.6.1 -jinja2==3.1.4 +jinja2==3.1.5 networkx==3.1 tenacity==8.2.3 diff --git a/requirements.txt b/requirements.txt index a8f60558..87faa2e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ requests>=2.24 pydantic>=2.0.0,<3.0.0 -jinja2==3.1.4 +jinja2==3.1.5 tenacity==8.2.3 urllib3>=1.26.0,<3 lazy_loader~=0.4 From 755ed4a62b72363f1470afa0bd72ca4ab1e7036e Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 13:26:11 +0530 Subject: [PATCH 39/66] Changed ignore_relationships = False to True nature of get_by_guid() and get_by_qualified_name() in the append_terms() --- pyatlan/client/asset.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index a6cd8f8d..e358614a 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1339,10 +1339,16 @@ def append_terms( if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid(guid=guid, asset_type=asset_type) + asset = self.get_by_guid( + guid=guid, + asset_type=asset_type, + ignore_relationships=True, # Sending minimal attributes, so relationships are excluded + ) elif qualified_name: asset = self.get_by_qualified_name( - qualified_name=qualified_name, asset_type=asset_type + qualified_name=qualified_name, + asset_type=asset_type, + ignore_relationships=True, # Sending minimal attributes, so relationships are excluded ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() From 83295abb6be3da98c56bb91a5fba07332577cc94 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 13:43:56 +0530 Subject: [PATCH 40/66] Updated unit tests to assert that ignore_relationships=True is passed, as this parameter is now being used in method calls --- tests/unit/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 676ef0ad..3748f8c0 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -303,7 +303,7 @@ def test_append_with_valid_guid_and_no_terms_returns_asset(): client.asset.append_terms(guid=guid, asset_type=asset_type, terms=terms) == table ) - mock_method.assert_called_once_with(guid=guid, asset_type=asset_type) + mock_method.assert_called_once_with(guid=guid, asset_type=asset_type, ignore_relationships=True) def test_append_with_valid_guid_when_no_terms_present_returns_asset_with_given_terms(): From 6d3b4002bb5db26a5dc5252c5c1da658015ecbdc Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 13:47:17 +0530 Subject: [PATCH 41/66] Fixed qa checks --- tests/unit/test_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 3748f8c0..c8abe442 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -303,7 +303,9 @@ def test_append_with_valid_guid_and_no_terms_returns_asset(): client.asset.append_terms(guid=guid, asset_type=asset_type, terms=terms) == table ) - mock_method.assert_called_once_with(guid=guid, asset_type=asset_type, ignore_relationships=True) + mock_method.assert_called_once_with( + guid=guid, asset_type=asset_type, ignore_relationships=True + ) def test_append_with_valid_guid_when_no_terms_present_returns_asset_with_given_terms(): From 7467f73cc04cdfb12b253bde9f5b54d6bd5f81be Mon Sep 17 00:00:00 2001 From: Ernest Hill Date: Thu, 2 Jan 2025 09:08:56 +0300 Subject: [PATCH 42/66] Modified to use regular expression --- pyatlan/client/workflow.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/workflow.py b/pyatlan/client/workflow.py index 54394e06..67d2799d 100644 --- a/pyatlan/client/workflow.py +++ b/pyatlan/client/workflow.py @@ -24,7 +24,7 @@ ) from pyatlan.errors import ErrorCode from pyatlan.model.enums import AtlanWorkflowPhase, WorkflowPackage -from pyatlan.model.search import Bool, NestedQuery, Prefix, Query, Term +from pyatlan.model.search import Bool, NestedQuery, Prefix, Query, Regexp, Term from pyatlan.model.workflow import ( ReRunRequest, ScheduleQueriesSearchRequest, @@ -85,10 +85,11 @@ def find_by_type( :raises ValidationError: If the provided prefix is invalid workflow package :raises AtlanError: on any API communication issue """ + regex = prefix.value.replace("-", "[-]") + "[-][0-9]{10}" query = Bool( filter=[ NestedQuery( - query=Prefix(field="metadata.name.keyword", value=prefix.value), + query=Regexp(field="metadata.name.keyword", value=regex), path="metadata", ) ] From fde3670ed62dd2c2247140745732ce3afce31d27 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 13:47:17 +0530 Subject: [PATCH 43/66] Fixed qa checks --- pyatlan/client/asset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index e358614a..807824e6 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1342,13 +1342,15 @@ def append_terms( asset = self.get_by_guid( guid=guid, asset_type=asset_type, - ignore_relationships=True, # Sending minimal attributes, so relationships are excluded + # Sending minimal attributes, so relationships are excluded + ignore_relationships=True, ) elif qualified_name: asset = self.get_by_qualified_name( qualified_name=qualified_name, asset_type=asset_type, - ignore_relationships=True, # Sending minimal attributes, so relationships are excluded + # Sending minimal attributes, so relationships are excluded + ignore_relationships=True, ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() From cf414606ebd987d88becf42dac6454e43b66ef78 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 23:06:21 +0530 Subject: [PATCH 44/66] reversing to the old state --- pyatlan/client/asset.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 807824e6..36794b90 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1342,15 +1342,13 @@ def append_terms( asset = self.get_by_guid( guid=guid, asset_type=asset_type, - # Sending minimal attributes, so relationships are excluded - ignore_relationships=True, + ignore_relationships=False, ) elif qualified_name: asset = self.get_by_qualified_name( qualified_name=qualified_name, asset_type=asset_type, - # Sending minimal attributes, so relationships are excluded - ignore_relationships=True, + ignore_relationships=False, ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() From 95dc583a65418369e82b2ebed24e600970789a16 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 23:13:41 +0530 Subject: [PATCH 45/66] Changed unit case from ignore_relationships=True to False as reversed back to original case --- tests/unit/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index c8abe442..080189bf 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -304,7 +304,7 @@ def test_append_with_valid_guid_and_no_terms_returns_asset(): == table ) mock_method.assert_called_once_with( - guid=guid, asset_type=asset_type, ignore_relationships=True + guid=guid, asset_type=asset_type, ignore_relationships=False ) From d8be596fe20c2f3ea150f28464c7a70aac2d543a Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 23:32:50 +0530 Subject: [PATCH 46/66] [Bug] Fixed an issue in BulkRequest where attributes were being retrieved based on the PyAtlan naming convention rather than the original API naming. This caused inconsistencies in the accessed attribute list, potentially leading to incorrect behavior. Adjusted retrieval logic to ensure alignment with the API --- pyatlan/model/core.py | 4 +++- testing.py | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 testing.py diff --git a/pyatlan/model/core.py b/pyatlan/model/core.py index 59582d1f..ce35d184 100644 --- a/pyatlan/model/core.py +++ b/pyatlan/model/core.py @@ -395,7 +395,9 @@ def process_relationship_attributes(cls, asset, attribute): replace_attributes = [] exclude_attributes = set() - attribute_name, attribute_value = attribute, getattr(asset, attribute, None) + # Updated to use `asset.attribute` instead of `asset` to align with the API. + # This change ensures the correct value is retrieved regardless of the naming conventions. + attribute_name, attribute_value = attribute, getattr(asset.attributes, attribute, None) # Process list of relationship attributes if attribute_value and isinstance(attribute_value, list): diff --git a/testing.py b/testing.py new file mode 100644 index 00000000..6f2a1a01 --- /dev/null +++ b/testing.py @@ -0,0 +1,46 @@ + + +from pyatlan.client.atlan import AtlanClient +from pyatlan.model.assets import Asset, Table +from pyatlan.model.enums import SaveSemantic +from pyatlan.model.fluent_search import FluentSearch, CompoundQuery +from pyatlan.model.assets.core.referenceable import AtlasGlossaryTerm +import logging +client = AtlanClient() +qn = "default/snowflake/1735595539/ANALYTICS/WIDE_WORLD_IMPORTERS/matillion_stg_airports" +term_qualified_name = "qZQt8hefUnbFwvCs48Kcl@LXNKR7hl7TLTPx1kKUK0V" +logging.basicConfig(level=logging.DEBUG) + +# search = ( +# FluentSearch() +# .select() +# .where(CompoundQuery.active_assets()) +# .where(Asset.QUALIFIED_NAME.eq(QN)) +# ) +# results = search.execute(client=client) +# if results and results.current_page(): +# first_result = results.current_page()[0] +# print(first_result) + +# response = client.asset.append_terms( # +# asset_type=Table, # +# qualified_name=qn, # +# terms=[AtlasGlossaryTerm.ref_by_qualified_name(qualified_name=, semantic= SaveSemantic.APPEND)], +# name="matillion_stg_airports" +# ) +asset_tables = Table.create_for_modification(qualified_name= qn,name = "matillion_stg_airports") +asset_tables.assigned_terms = [AtlasGlossaryTerm.ref_by_guid(guid="1025d13b-24d6-404d-80fd-869e72be7e00", semantic=SaveSemantic.APPEND)] +response = client.asset.save(asset_tables) +print(response) + +# import ipdb; ipdb.set_trace() +# guid1 = "e60a0cb8-d416-4e21-b70a-a56a7b6cfc19" +# term = AtlasGlossaryTerm.create_for_modification( +# qualified_name="ZWm178w8rfKUNWnoccghL@2kS6ivv9A3sMEmQawU26z", +# name="test1", +# glossary_guid="387df689-82e5-49c6-b77d-038222c12c34", +# ) +# term.see_also = [ +# AtlasGlossaryTerm.ref_by_guid(guid="1025d13b-24d6-404d-80fd-869e72be7e00", semantic=SaveSemantic.APPEND), +# ] +# response = client.asset.save(term) \ No newline at end of file From 529e43d9b5d9d5e13344fddaaaf10600f80c3e12 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 2 Jan 2025 23:38:31 +0530 Subject: [PATCH 47/66] Fixed QA checks --- pyatlan/model/core.py | 4 +++- testing.py | 46 ------------------------------------------- 2 files changed, 3 insertions(+), 47 deletions(-) delete mode 100644 testing.py diff --git a/pyatlan/model/core.py b/pyatlan/model/core.py index ce35d184..f94add1c 100644 --- a/pyatlan/model/core.py +++ b/pyatlan/model/core.py @@ -397,7 +397,9 @@ def process_relationship_attributes(cls, asset, attribute): # Updated to use `asset.attribute` instead of `asset` to align with the API. # This change ensures the correct value is retrieved regardless of the naming conventions. - attribute_name, attribute_value = attribute, getattr(asset.attributes, attribute, None) + attribute_name, attribute_value = attribute, getattr( + asset.attributes, attribute, None + ) # Process list of relationship attributes if attribute_value and isinstance(attribute_value, list): diff --git a/testing.py b/testing.py deleted file mode 100644 index 6f2a1a01..00000000 --- a/testing.py +++ /dev/null @@ -1,46 +0,0 @@ - - -from pyatlan.client.atlan import AtlanClient -from pyatlan.model.assets import Asset, Table -from pyatlan.model.enums import SaveSemantic -from pyatlan.model.fluent_search import FluentSearch, CompoundQuery -from pyatlan.model.assets.core.referenceable import AtlasGlossaryTerm -import logging -client = AtlanClient() -qn = "default/snowflake/1735595539/ANALYTICS/WIDE_WORLD_IMPORTERS/matillion_stg_airports" -term_qualified_name = "qZQt8hefUnbFwvCs48Kcl@LXNKR7hl7TLTPx1kKUK0V" -logging.basicConfig(level=logging.DEBUG) - -# search = ( -# FluentSearch() -# .select() -# .where(CompoundQuery.active_assets()) -# .where(Asset.QUALIFIED_NAME.eq(QN)) -# ) -# results = search.execute(client=client) -# if results and results.current_page(): -# first_result = results.current_page()[0] -# print(first_result) - -# response = client.asset.append_terms( # -# asset_type=Table, # -# qualified_name=qn, # -# terms=[AtlasGlossaryTerm.ref_by_qualified_name(qualified_name=, semantic= SaveSemantic.APPEND)], -# name="matillion_stg_airports" -# ) -asset_tables = Table.create_for_modification(qualified_name= qn,name = "matillion_stg_airports") -asset_tables.assigned_terms = [AtlasGlossaryTerm.ref_by_guid(guid="1025d13b-24d6-404d-80fd-869e72be7e00", semantic=SaveSemantic.APPEND)] -response = client.asset.save(asset_tables) -print(response) - -# import ipdb; ipdb.set_trace() -# guid1 = "e60a0cb8-d416-4e21-b70a-a56a7b6cfc19" -# term = AtlasGlossaryTerm.create_for_modification( -# qualified_name="ZWm178w8rfKUNWnoccghL@2kS6ivv9A3sMEmQawU26z", -# name="test1", -# glossary_guid="387df689-82e5-49c6-b77d-038222c12c34", -# ) -# term.see_also = [ -# AtlasGlossaryTerm.ref_by_guid(guid="1025d13b-24d6-404d-80fd-869e72be7e00", semantic=SaveSemantic.APPEND), -# ] -# response = client.asset.save(term) \ No newline at end of file From 68dd0308110d2d22d31a090200cadeadd3cdd15e Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 14:14:24 +0530 Subject: [PATCH 48/66] Revert "Merge branch 'FT-843' into FT-887" This reverts commit 90f281bf04ef25f925b925ff821e222e8b25d4ed, reversing changes made to 529e43d9b5d9d5e13344fddaaaf10600f80c3e12. --- pyatlan/model/enums.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyatlan/model/enums.py b/pyatlan/model/enums.py index fc95ee90..073e8e63 100644 --- a/pyatlan/model/enums.py +++ b/pyatlan/model/enums.py @@ -337,7 +337,6 @@ def get_connector_name( IBM_DB2 = ("ibmdb2", AtlanConnectionCategory.DATABASE) APP = ("app", AtlanConnectionCategory.APP) BIGID = ("bigid", AtlanConnectionCategory.SAAS) - ANAPLAN = ("anaplan", AtlanConnectionCategory.BI) AWS_BATCH = ("aws-batch", AtlanConnectionCategory.ELT) AWS_ECS = ("aws-ecs", AtlanConnectionCategory.ELT) AWS_LAMBDA = ("aws-lambda", AtlanConnectionCategory.ELT) From 3a0d4c73716676e7e1186463c7cbe92a3b70f8ff Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 14:28:09 +0530 Subject: [PATCH 49/66] [Bug] Fixed an issue in BulkRequest where attributes were being retrieved based on the PyAtlan naming convention rather than the original API naming. This caused inconsistencies in the accessed attribute list, potentially leading to incorrect behavior. Adjusted retrieval logic to ensure alignment with the API --- pyatlan/model/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyatlan/model/core.py b/pyatlan/model/core.py index f94add1c..4a7f9155 100644 --- a/pyatlan/model/core.py +++ b/pyatlan/model/core.py @@ -422,7 +422,9 @@ def process_relationship_attributes(cls, asset, attribute): {to_camel_case(attribute_name): append_attributes} ) if replace_attributes: - setattr(asset, attribute_name, replace_attributes) + # Updated to use `asset.attribute` instead of `asset` to align with the API. + # This change ensures the correct value is retrieved regardless of the naming conventions. + setattr(asset.attributes, attribute_name, replace_attributes) # If 'remove', 'append', or both attributes are present and there are no 'replace' attributes, # add the attribute to the set to exclude it from the bulk request payload. From dee237d353cc1120226dda86b6596fa605c5cc21 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Fri, 3 Jan 2025 14:31:21 +0530 Subject: [PATCH 50/66] Changed by mistake: enums.py --- pyatlan/model/enums.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyatlan/model/enums.py b/pyatlan/model/enums.py index 073e8e63..fc95ee90 100644 --- a/pyatlan/model/enums.py +++ b/pyatlan/model/enums.py @@ -337,6 +337,7 @@ def get_connector_name( IBM_DB2 = ("ibmdb2", AtlanConnectionCategory.DATABASE) APP = ("app", AtlanConnectionCategory.APP) BIGID = ("bigid", AtlanConnectionCategory.SAAS) + ANAPLAN = ("anaplan", AtlanConnectionCategory.BI) AWS_BATCH = ("aws-batch", AtlanConnectionCategory.ELT) AWS_ECS = ("aws-ecs", AtlanConnectionCategory.ELT) AWS_LAMBDA = ("aws-lambda", AtlanConnectionCategory.ELT) From 7192b7fe1691a1ba46bf0d7537fd5dd312534842 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 15:13:22 +0530 Subject: [PATCH 51/66] Updated the implementation of `append_terms()`, `replace_terms()`, and `remove_terms()` to utilize backend-driven append, replace, and remove operations. --- pyatlan/client/asset.py | 175 ++++++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 51 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 36794b90..12aad88b 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -83,6 +83,7 @@ AtlanDeleteType, CertificateStatus, EntityStatus, + SaveSemantic, SortOrder, ) from pyatlan.model.fields.atlan_fields import AtlanField @@ -1336,35 +1337,56 @@ def append_terms( :param qualified_name: the qualified_name of the asset to which to link the terms :returns: the asset that was updated (note that it will NOT contain details of the appended terms) """ + from pyatlan.client.atlan import AtlanClient + from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid( - guid=guid, - asset_type=asset_type, - ignore_relationships=False, + client = AtlanClient.get_default_client() + search = ( + FluentSearch() + .select() + .where(CompoundQuery.active_assets()) + .where(Asset.GUID.eq(guid)) + .execute(client=client) ) + if search and search.current_page(): + first_result = search.current_page()[0] + if not isinstance(first_result, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater( + qualified_name=qualified_name, name=name + ) + + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) + elif qualified_name: - asset = self.get_by_qualified_name( - qualified_name=qualified_name, - asset_type=asset_type, - ignore_relationships=False, - ) + name = qualified_name.split("/")[-1] + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) + else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - if not terms: - return asset - replacement_terms: List[AtlasGlossaryTerm] = [] - if existing_terms := asset.assigned_terms: - replacement_terms.extend( - term for term in existing_terms if term.relationship_status != "DELETED" - ) - replacement_terms.extend(terms) - asset.assigned_terms = replacement_terms - response = self.save(entity=asset) + + for i, term in enumerate(terms): + if hasattr(term, "guid") and term.guid: + terms[i] = AtlasGlossaryTerm.ref_by_guid( + guid=term.guid, semantic=SaveSemantic.APPEND + ) + elif hasattr(term, "qualified_name") and term.qualified_name: + terms[i] = AtlasGlossaryTerm.ref_by_qualified_name( + qualified_name=term.qualified_name, semantic=SaveSemantic.APPEND + ) + updated_asset.assigned_terms = terms + response = self.save(entity=updated_asset) if assets := response.assets_updated(asset_type=asset_type): return assets[0] - return asset + return updated_asset @validate_arguments def replace_terms( @@ -1384,25 +1406,56 @@ def replace_terms( :param qualified_name: the qualified_name of the asset to which to replace the terms :returns: the asset that was updated (note that it will NOT contain details of the replaced terms) """ + from pyatlan.client.atlan import AtlanClient + from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid( - guid=guid, asset_type=asset_type, ignore_relationships=False + client = AtlanClient.get_default_client() + search = ( + FluentSearch() + .select() + .where(CompoundQuery.active_assets()) + .where(Asset.GUID.eq(guid)) + .execute(client=client) ) + if search and search.current_page(): + first_result = search.current_page()[0] + if not isinstance(first_result, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater( + qualified_name=qualified_name, name=name + ) + + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) + elif qualified_name: - asset = self.get_by_qualified_name( - qualified_name=qualified_name, - asset_type=asset_type, - ignore_relationships=False, - ) + name = qualified_name.split("/")[-1] + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) + else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - asset.assigned_terms = terms - response = self.save(entity=asset) + + for i, term in enumerate(terms): + if hasattr(term, "guid") and term.guid: + terms[i] = AtlasGlossaryTerm.ref_by_guid( + guid=term.guid, semantic=SaveSemantic.REPLACE + ) + elif hasattr(term, "qualified_name") and term.qualified_name: + terms[i] = AtlasGlossaryTerm.ref_by_qualified_name( + qualified_name=term.qualified_name, semantic=SaveSemantic.REPLACE + ) + updated_asset.assigned_terms = terms + response = self.save(entity=updated_asset) if assets := response.assets_updated(asset_type=asset_type): return assets[0] - return asset + return updated_asset @validate_arguments def remove_terms( @@ -1424,36 +1477,56 @@ def remove_terms( :param qualified_name: the qualified_name of the asset from which to remove the terms :returns: the asset that was updated (note that it will NOT contain details of the resulting terms) """ - if not terms: - raise ErrorCode.MISSING_TERMS.exception_with_parameters() + from pyatlan.client.atlan import AtlanClient + from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - asset = self.get_by_guid( - guid=guid, asset_type=asset_type, ignore_relationships=False + client = AtlanClient.get_default_client() + search = ( + FluentSearch() + .select() + .where(CompoundQuery.active_assets()) + .where(Asset.GUID.eq(guid)) + .execute(client=client) ) + if search and search.current_page(): + first_result = search.current_page()[0] + if not isinstance(first_result, asset_type): + raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( + guid, asset_type.__name__ + ) + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater( + qualified_name=qualified_name, name=name + ) + + else: + raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) + elif qualified_name: - asset = self.get_by_qualified_name( - qualified_name=qualified_name, - asset_type=asset_type, - ignore_relationships=False, - ) + name = qualified_name.split("/")[-1] + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) + else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - replacement_terms: List[AtlasGlossaryTerm] = [] - guids_to_be_removed = {t.guid for t in terms} - if existing_terms := asset.assigned_terms: - replacement_terms.extend( - term - for term in existing_terms - if term.relationship_status != "DELETED" - and term.guid not in guids_to_be_removed - ) - asset.assigned_terms = replacement_terms - response = self.save(entity=asset) + + for i, term in enumerate(terms): + if hasattr(term, "guid") and term.guid: + terms[i] = AtlasGlossaryTerm.ref_by_guid( + guid=term.guid, semantic=SaveSemantic.REMOVE + ) + elif hasattr(term, "qualified_name") and term.qualified_name: + terms[i] = AtlasGlossaryTerm.ref_by_qualified_name( + qualified_name=term.qualified_name, semantic=SaveSemantic.REMOVE + ) + updated_asset.assigned_terms = terms + response = self.save(entity=updated_asset) if assets := response.assets_updated(asset_type=asset_type): return assets[0] - return asset + return updated_asset @validate_arguments def find_connections_by_name( From b96b5a3e542cbecd81057c71bb14ffa94590513a Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 17:47:26 +0530 Subject: [PATCH 52/66] included fluent search for qualified_name as well for append_terms(),replace_terms(),remove_terms() --- pyatlan/client/asset.py | 156 +++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 12aad88b..44648850 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1339,40 +1339,42 @@ def append_terms( """ from pyatlan.client.atlan import AtlanClient from pyatlan.model.fluent_search import CompoundQuery, FluentSearch - - if guid: - if qualified_name: - raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - client = AtlanClient.get_default_client() - search = ( + client = AtlanClient.get_default_client() + search = ( FluentSearch() .select() - .where(CompoundQuery.active_assets()) - .where(Asset.GUID.eq(guid)) - .execute(client=client) ) - if search and search.current_page(): - first_result = search.current_page()[0] - if not isinstance(first_result, asset_type): + if guid: + if qualified_name: + raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() + search = search.where(Asset.GUID.eq(guid)) + elif qualified_name: + search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + else: + raise ErrorCode.QN_OR_GUID.exception_with_parameters() + + results = search.execute(client=client) + if results and results.current_page(): + first_result = results.current_page()[0] + if not isinstance(first_result, asset_type): + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + else: raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( guid, asset_type.__name__ ) - qualified_name = first_result.qualified_name - name = first_result.name - updated_asset = asset_type.updater( - qualified_name=qualified_name, name=name + else: + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( + qualified_name, asset_type.__name__ ) - else: raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) - - elif qualified_name: - name = qualified_name.split("/")[-1] - updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) - - else: - raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) for i, term in enumerate(terms): if hasattr(term, "guid") and term.guid: terms[i] = AtlasGlossaryTerm.ref_by_guid( @@ -1408,40 +1410,42 @@ def replace_terms( """ from pyatlan.client.atlan import AtlanClient from pyatlan.model.fluent_search import CompoundQuery, FluentSearch - - if guid: - if qualified_name: - raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - client = AtlanClient.get_default_client() - search = ( + client = AtlanClient.get_default_client() + search = ( FluentSearch() .select() - .where(CompoundQuery.active_assets()) - .where(Asset.GUID.eq(guid)) - .execute(client=client) ) - if search and search.current_page(): - first_result = search.current_page()[0] - if not isinstance(first_result, asset_type): + if guid: + if qualified_name: + raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() + search = search.where(Asset.GUID.eq(guid)) + elif qualified_name: + search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + else: + raise ErrorCode.QN_OR_GUID.exception_with_parameters() + + results = search.execute(client=client) + if results and results.current_page(): + first_result = results.current_page()[0] + if not isinstance(first_result, asset_type): + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + else: raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( guid, asset_type.__name__ ) - qualified_name = first_result.qualified_name - name = first_result.name - updated_asset = asset_type.updater( - qualified_name=qualified_name, name=name + else: + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( + qualified_name, asset_type.__name__ ) - else: raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) - - elif qualified_name: - name = qualified_name.split("/")[-1] - updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) - - else: - raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) for i, term in enumerate(terms): if hasattr(term, "guid") and term.guid: terms[i] = AtlasGlossaryTerm.ref_by_guid( @@ -1479,40 +1483,42 @@ def remove_terms( """ from pyatlan.client.atlan import AtlanClient from pyatlan.model.fluent_search import CompoundQuery, FluentSearch - - if guid: - if qualified_name: - raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - client = AtlanClient.get_default_client() - search = ( + client = AtlanClient.get_default_client() + search = ( FluentSearch() .select() - .where(CompoundQuery.active_assets()) - .where(Asset.GUID.eq(guid)) - .execute(client=client) ) - if search and search.current_page(): - first_result = search.current_page()[0] - if not isinstance(first_result, asset_type): + if guid: + if qualified_name: + raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() + search = search.where(Asset.GUID.eq(guid)) + elif qualified_name: + search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + else: + raise ErrorCode.QN_OR_GUID.exception_with_parameters() + + results = search.execute(client=client) + if results and results.current_page(): + first_result = results.current_page()[0] + if not isinstance(first_result, asset_type): + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_NAME.exception_with_parameters( + asset_type.__name__, qualified_name + ) + else: raise ErrorCode.ASSET_NOT_TYPE_REQUESTED.exception_with_parameters( guid, asset_type.__name__ ) - qualified_name = first_result.qualified_name - name = first_result.name - updated_asset = asset_type.updater( - qualified_name=qualified_name, name=name + else: + if guid is None: + raise ErrorCode.ASSET_NOT_FOUND_BY_QN.exception_with_parameters( + qualified_name, asset_type.__name__ ) - else: raise ErrorCode.ASSET_NOT_FOUND_BY_GUID.exception_with_parameters(guid) - - elif qualified_name: - name = qualified_name.split("/")[-1] - updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) - - else: - raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + qualified_name = first_result.qualified_name + name = first_result.name + updated_asset = asset_type.updater(qualified_name=qualified_name, name=name) for i, term in enumerate(terms): if hasattr(term, "guid") and term.guid: terms[i] = AtlasGlossaryTerm.ref_by_guid( From 30a151fa8ed9397b3a860712fe249d2be79c89b7 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 17:49:55 +0530 Subject: [PATCH 53/66] Fixed QA checks --- pyatlan/client/asset.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 44648850..1cf4768d 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1338,12 +1338,10 @@ def append_terms( :returns: the asset that was updated (note that it will NOT contain details of the appended terms) """ from pyatlan.client.atlan import AtlanClient - from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + from pyatlan.model.fluent_search import FluentSearch + client = AtlanClient.get_default_client() - search = ( - FluentSearch() - .select() - ) + search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() @@ -1352,7 +1350,7 @@ def append_terms( search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] @@ -1409,12 +1407,10 @@ def replace_terms( :returns: the asset that was updated (note that it will NOT contain details of the replaced terms) """ from pyatlan.client.atlan import AtlanClient - from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + from pyatlan.model.fluent_search import FluentSearch + client = AtlanClient.get_default_client() - search = ( - FluentSearch() - .select() - ) + search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() @@ -1423,7 +1419,7 @@ def replace_terms( search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] @@ -1482,12 +1478,10 @@ def remove_terms( :returns: the asset that was updated (note that it will NOT contain details of the resulting terms) """ from pyatlan.client.atlan import AtlanClient - from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + from pyatlan.model.fluent_search import FluentSearch + client = AtlanClient.get_default_client() - search = ( - FluentSearch() - .select() - ) + search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() @@ -1496,7 +1490,7 @@ def remove_terms( search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - + results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] From e131a1f9a79e5f44c4e3cab622852c14cb940cf8 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 18:09:07 +0530 Subject: [PATCH 54/66] Resolved Conversations --- pyatlan/client/asset.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index a6cd8f8d..de26094c 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -358,8 +358,8 @@ def get_by_qualified_name( asset_type: Type[A], min_ext_info: bool = False, ignore_relationships: bool = True, - attributes: Optional[List[str]] = None, - relationships_attributes: Optional[List[str]] = None, + attributes: Optional[Union[List[str], List[AtlanField]]] = None, + relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None ) -> A: """ Retrieves an asset by its qualified_name. @@ -389,15 +389,12 @@ def get_by_qualified_name( search = ( FluentSearch() .select() - .where(CompoundQuery.active_assets()) .where(Asset.QUALIFIED_NAME.eq(qualified_name)) ) - if attributes: - for attribute in attributes: - search = search.include_on_results(attribute) - if relationships_attributes: - for relation_attribute in relationships_attributes: - search = search.include_on_relations(relation_attribute) + for attribute in attributes: + search = search.include_on_results(attribute) + for relation_attribute in relationships_attributes: + search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] @@ -434,8 +431,8 @@ def get_by_guid( asset_type: Type[A] = Asset, # type: ignore[assignment] min_ext_info: bool = False, ignore_relationships: bool = True, - attributes: Optional[List[str]] = None, - relationships_attributes: Optional[List[str]] = None, + attributes: Optional[Union[List[str], List[AtlanField]]] = None, + relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None ) -> A: """ Retrieves an asset by its GUID. @@ -464,15 +461,12 @@ def get_by_guid( search = ( FluentSearch() .select() - .where(CompoundQuery.active_assets()) .where(Asset.GUID.eq(guid)) ) - if attributes: - for attribute in attributes: - search = search.include_on_results(attribute) - if relationships_attributes: - for relation_attribute in relationships_attributes: - search = search.include_on_relations(relation_attribute) + for attribute in attributes: + search = search.include_on_results(attribute) + for relation_attribute in relationships_attributes: + search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] From d71a7643d2b3df08607e48e76f26d26e40b970b9 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 18:20:30 +0530 Subject: [PATCH 55/66] Fixed QA checks --- pyatlan/client/asset.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index de26094c..75e4d004 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -359,7 +359,7 @@ def get_by_qualified_name( min_ext_info: bool = False, ignore_relationships: bool = True, attributes: Optional[Union[List[str], List[AtlanField]]] = None, - relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None + relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None, ) -> A: """ Retrieves an asset by its qualified_name. @@ -375,7 +375,7 @@ def get_by_qualified_name( :raises AtlanError: on any API communication issue """ from pyatlan.client.atlan import AtlanClient - from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + from pyatlan.model.fluent_search import FluentSearch query_params = { "attr:qualifiedName": qualified_name, @@ -387,13 +387,13 @@ def get_by_qualified_name( ): client = AtlanClient.get_default_client() search = ( - FluentSearch() - .select() - .where(Asset.QUALIFIED_NAME.eq(qualified_name)) + FluentSearch().select().where(Asset.QUALIFIED_NAME.eq(qualified_name)) ) - for attribute in attributes: + for attribute in attributes: # type: ignore[union-attr] search = search.include_on_results(attribute) - for relation_attribute in relationships_attributes: + for ( + relation_attribute + ) in relationships_attributes: # type: ignore[union-attr] search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): @@ -432,7 +432,7 @@ def get_by_guid( min_ext_info: bool = False, ignore_relationships: bool = True, attributes: Optional[Union[List[str], List[AtlanField]]] = None, - relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None + relationships_attributes: Optional[Union[List[str], List[AtlanField]]] = None, ) -> A: """ Retrieves an asset by its GUID. @@ -448,7 +448,7 @@ def get_by_guid( :raises AtlanError: on any API communication issue """ from pyatlan.client.atlan import AtlanClient - from pyatlan.model.fluent_search import CompoundQuery, FluentSearch + from pyatlan.model.fluent_search import FluentSearch query_params = { "minExtInfo": min_ext_info, @@ -458,14 +458,10 @@ def get_by_guid( relationships_attributes and len(relationships_attributes) ): client = AtlanClient.get_default_client() - search = ( - FluentSearch() - .select() - .where(Asset.GUID.eq(guid)) - ) - for attribute in attributes: + search = FluentSearch().select().where(Asset.GUID.eq(guid)) + for attribute in attributes: # type: ignore[union-attr] search = search.include_on_results(attribute) - for relation_attribute in relationships_attributes: + for relation_attribute in relationships_attributes: # type: ignore[union-attr] search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): From 2b7ad04977276c21de526e4c21d13987f27ca244 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 20:38:36 +0530 Subject: [PATCH 56/66] Changed the Unit Tests --- tests/unit/test_client.py | 376 +++++++++++++++++++------------------- 1 file changed, 191 insertions(+), 185 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 080189bf..19c9fa61 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -236,144 +236,108 @@ def glossary_category_by_name_json(): @pytest.mark.parametrize( - "guid, qualified_name, asset_type, assigned_terms, message, error", + "guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error", [ ( - "123", None, - Table, None, - "1 validation error for AppendTerms\\nterms\\n none is not an allowed value ", - ValueError, + Table, + [AtlasGlossaryTerm()], + "ATLAN-PYTHON-400-043 Either qualified_name or guid should be provided.", + InvalidRequestError, ), ( "123", + "default/abc", + Table, + [AtlasGlossaryTerm()], + "ATLAN-PYTHON-400-042 Only qualified_name or guid should be provided but not both.", + InvalidRequestError, + ), + ], +) +def test_append_terms_invalid_parameters_raises_error( + guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error +): + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.append_terms( + asset_type=asset_type, + terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, + ) + + +@pytest.mark.parametrize( + "guid, qualified_name, asset_type, assigned_terms, mock_results, expected_message, expected_error", + [ + ( None, - None, + "nonexistent_qualified_name", + Table, [AtlasGlossaryTerm()], - "1 validation error for AppendTerms\\nasset_type\\n none is not an allowed value ", - ValueError, + [], + "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist. " + "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + NotFoundError, ), ( + "nonexistent_guid", None, + Table, + [AtlasGlossaryTerm()], + [], + "ATLAN-PYTHON-404-001 Asset with GUID nonexistent_guid does not exist." + " Suggestion: Verify the GUID of the asset you are trying to retrieve.", + NotFoundError, + ), + ( None, + "default/abc", Table, [AtlasGlossaryTerm()], - "ATLAN-PYTHON-400-043 Either qualified_name or guid should be provided.", - InvalidRequestError, + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." + "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + NotFoundError, ), ( "123", - "default/abc", + None, Table, [AtlasGlossaryTerm()], - "ATLAN-PYTHON-400-042 Only qualified_name or guid should be provided but not both.", - InvalidRequestError, + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." + "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + NotFoundError, ), ], ) -def test_append_terms_with_invalid_parameter_raises_error( +@patch("pyatlan.model.fluent_search.FluentSearch.execute") +def test_append_terms_asset_retrieval_errors( + mock_execute, guid, qualified_name, asset_type, assigned_terms, - message, - error, - client: AtlanClient, + mock_results, + expected_message, + expected_error, ): - with pytest.raises(error, match=message): - client.asset.append_terms( - guid=guid, - qualified_name=qualified_name, + mock_execute.return_value.current_page = lambda: mock_results + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.append_terms( asset_type=asset_type, terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, ) -def test_append_with_valid_guid_and_no_terms_returns_asset(): - asset_type = Table - table = asset_type() - - with patch.object(AssetClient, "get_by_guid", return_value=table) as mock_method: - client = AtlanClient() - guid = "123" - terms = [] - - assert ( - client.asset.append_terms(guid=guid, asset_type=asset_type, terms=terms) - == table - ) - mock_method.assert_called_once_with( - guid=guid, asset_type=asset_type, ignore_relationships=False - ) - - -def test_append_with_valid_guid_when_no_terms_present_returns_asset_with_given_terms(): - asset_type = Table - with patch.multiple(AssetClient, get_by_guid=DEFAULT, save=DEFAULT) as mock_methods: - table = Table() - mock_methods["get_by_guid"].return_value = table - mock_methods["save"].return_value.assets_updated.return_value = [table] - client = AtlanClient() - guid = "123" - terms = [AtlasGlossaryTerm()] - - assert ( - asset := client.asset.append_terms( - guid=guid, asset_type=asset_type, terms=terms - ) - ) - assert asset.assigned_terms == terms - - -def test_append_with_valid_guid_when_deleted_terms_present_returns_asset_with_given_terms(): - asset_type = Table - with patch.multiple(AssetClient, get_by_guid=DEFAULT, save=DEFAULT) as mock_methods: - table = Table(attributes=Table.Attributes()) - term = AtlasGlossaryTerm() - term.relationship_status = "DELETED" - table.attributes.meanings = [term] - mock_methods["get_by_guid"].return_value = table - mock_methods["save"].return_value.assets_updated.return_value = [table] - client = AtlanClient() - guid = "123" - terms = [AtlasGlossaryTerm()] - - assert ( - asset := client.asset.append_terms( - guid=guid, asset_type=asset_type, terms=terms - ) - ) - assert asset.assigned_terms == terms - - -def test_append_with_valid_guid_when_terms_present_returns_asset_with_combined_terms(): - asset_type = Table - with patch.multiple(AssetClient, get_by_guid=DEFAULT, save=DEFAULT) as mock_methods: - table = Table(attributes=Table.Attributes()) - exisiting_term = AtlasGlossaryTerm() - table.attributes.meanings = [exisiting_term] - mock_methods["get_by_guid"].return_value = table - mock_methods["save"].return_value.assets_updated.return_value = [table] - client = AtlanClient() - guid = "123" - - new_term = AtlasGlossaryTerm() - terms = [new_term] - - assert ( - asset := client.asset.append_terms( - guid=guid, asset_type=asset_type, terms=terms - ) - ) - assert (updated_terms := asset.assigned_terms) - assert len(updated_terms) == 2 - assert exisiting_term in updated_terms - assert new_term in updated_terms - - @pytest.mark.parametrize( - "guid, qualified_name, asset_type, assigned_terms, message, error", + "guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error", [ ( None, @@ -385,68 +349,96 @@ def test_append_with_valid_guid_when_terms_present_returns_asset_with_combined_t ), ( "123", + "default/abc", + Table, + [AtlasGlossaryTerm()], + "ATLAN-PYTHON-400-042 Only qualified_name or guid should be provided but not both.", + InvalidRequestError, + ), + ], +) +def test_replace_terms_invalid_parameters_raises_error( + guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error +): + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.replace_terms( + asset_type=asset_type, + terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, + ) + + +@pytest.mark.parametrize( + "guid, qualified_name, asset_type, assigned_terms, mock_results, expected_message, expected_error", + [ + ( None, + "nonexistent_qualified_name", + Table, + [AtlasGlossaryTerm()], + [], + "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist." + "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + NotFoundError, + ), + ( + "nonexistent_guid", None, + Table, [AtlasGlossaryTerm()], - "1 validation error for ReplaceTerms\\nasset_type\\n none is not an allowed value ", - ValueError, + [], + "ATLAN-PYTHON-404-001 Asset with GUID nonexistent_guid does not exist." + "Suggestion: Verify the GUID of the asset you are trying to retrieve.", + NotFoundError, ), ( - "123", + None, "default/abc", Table, [AtlasGlossaryTerm()], - "ATLAN-PYTHON-400-042 Only qualified_name or guid should be provided but not both.", - InvalidRequestError, + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." + "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + NotFoundError, ), ( "123", None, Table, - None, - "1 validation error for ReplaceTerms\\nterms\\n none is not an allowed value ", - ValueError, + [AtlasGlossaryTerm()], + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." + "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + NotFoundError, ), ], ) -def test_replace_terms_with_invalid_parameter_raises_error( +@patch("pyatlan.model.fluent_search.FluentSearch.execute") +def test_replace_terms_asset_retrieval_errors( + mock_execute, guid, qualified_name, asset_type, assigned_terms, - message, - error, - client: AtlanClient, + mock_results, + expected_message, + expected_error, ): - with pytest.raises(error, match=message): - client.asset.replace_terms( - guid=guid, - qualified_name=qualified_name, + mock_execute.return_value.current_page = lambda: mock_results + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.replace_terms( asset_type=asset_type, terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, ) -def test_replace_terms(): - asset_type = Table - with patch.multiple(AssetClient, get_by_guid=DEFAULT, save=DEFAULT) as mock_methods: - table = Table() - mock_methods["get_by_guid"].return_value = table - mock_methods["save"].return_value.assets_updated.return_value = [table] - client = AtlanClient() - guid = "123" - terms = [AtlasGlossaryTerm()] - - assert ( - asset := client.asset.replace_terms( - guid=guid, asset_type=asset_type, terms=terms - ) - ) - assert asset.assigned_terms == terms - - @pytest.mark.parametrize( - "guid, qualified_name, asset_type, assigned_terms, message, error", + "guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error", [ ( None, @@ -456,14 +448,6 @@ def test_replace_terms(): "ATLAN-PYTHON-400-043 Either qualified_name or guid should be provided.", InvalidRequestError, ), - ( - "123", - None, - None, - [AtlasGlossaryTerm()], - "1 validation error for RemoveTerms\\nasset_type\\n none is not an allowed value ", - ValueError, - ), ( "123", "default/abc", @@ -472,66 +456,88 @@ def test_replace_terms(): "ATLAN-PYTHON-400-042 Only qualified_name or guid should be provided but not both.", InvalidRequestError, ), + ], +) +def test_remove_terms_invalid_parameters_raises_error( + guid, qualified_name, asset_type, assigned_terms, expected_message, expected_error +): + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.remove_terms( + asset_type=asset_type, + terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, + ) + + +@pytest.mark.parametrize( + "guid, qualified_name, asset_type, assigned_terms, mock_results, expected_message, expected_error", + [ ( - "123", + None, + "nonexistent_qualified_name", + Table, + [AtlasGlossaryTerm()], + [], + "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist." + "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + NotFoundError, + ), + ( + "nonexistent_guid", None, Table, + [AtlasGlossaryTerm()], + [], + "ATLAN-PYTHON-404-001 Asset with GUID nonexistent_guid does not exist." + "Suggestion: Verify the GUID of the asset you are trying to retrieve.", + NotFoundError, + ), + ( None, - "1 validation error for RemoveTerms\\nterms\\n none is not an allowed value ", - ValueError, + "default/abc", + Table, + [AtlasGlossaryTerm()], + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." + "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + NotFoundError, ), ( "123", None, Table, - [], - "ATLAN-PYTHON-400-044 A list of assigned_terms to remove must be specified.", - InvalidRequestError, + [AtlasGlossaryTerm()], + ["DifferentTypeAsset"], + "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." + "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + NotFoundError, ), ], ) -def test_remove_terms_with_invalid_parameter_raises_error( +@patch("pyatlan.model.fluent_search.FluentSearch.execute") +def test_remove_terms_asset_retrieval_errors( + mock_execute, guid, qualified_name, asset_type, assigned_terms, - message, - error, - client: AtlanClient, + mock_results, + expected_message, + expected_error, ): - with pytest.raises(error, match=message): - client.asset.remove_terms( - guid=guid, - qualified_name=qualified_name, + mock_execute.return_value.current_page = lambda: mock_results + client = AtlanClient() + with pytest.raises(expected_error, match=expected_message): + client.remove_terms( asset_type=asset_type, terms=assigned_terms, + guid=guid, + qualified_name=qualified_name, ) -def test_remove_with_valid_guid_when_terms_present_returns_asset_with_terms_removed(): - asset_type = Table - with patch.multiple(AssetClient, get_by_guid=DEFAULT, save=DEFAULT) as mock_methods: - table = Table(attributes=Table.Attributes()) - exisiting_term = AtlasGlossaryTerm() - exisiting_term.guid = "b4113341-251b-4adc-81fb-2420501c30e6" - other_term = AtlasGlossaryTerm() - other_term.guid = "b267858d-8316-4c41-a56a-6e9b840cef4a" - table.attributes.meanings = [exisiting_term, other_term] - mock_methods["get_by_guid"].return_value = table - mock_methods["save"].return_value.assets_updated.return_value = [table] - client = AtlanClient() - guid = "123" - - assert ( - asset := client.asset.remove_terms( - guid=guid, asset_type=asset_type, terms=[exisiting_term] - ) - ) - assert (updated_terms := asset.assigned_terms) - assert len(updated_terms) == 1 - assert other_term in updated_terms - - def test_register_client_with_bad_parameter_raises_value_error(client): with pytest.raises( InvalidRequestError, match="client must be an instance of AtlanClient" From 049ba0950ab37ffb42d630b773843bee0a6ab5ec Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 3 Jan 2025 23:19:31 +0530 Subject: [PATCH 57/66] Small changes to the fluent search implementations structure --- pyatlan/client/asset.py | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 1cf4768d..c7d40346 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -1341,17 +1341,25 @@ def append_terms( from pyatlan.model.fluent_search import FluentSearch client = AtlanClient.get_default_client() - search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - search = search.where(Asset.GUID.eq(guid)) + results = ( + FluentSearch() + .select() + .where(asset_type.GUID.eq(guid)) + .execute(client=client) + ) elif qualified_name: - search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + results = ( + FluentSearch() + .select() + .where(asset_type.QUALIFIED_NAME.eq(qualified_name)) + .execute(client=client) + ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] if not isinstance(first_result, asset_type): @@ -1410,17 +1418,25 @@ def replace_terms( from pyatlan.model.fluent_search import FluentSearch client = AtlanClient.get_default_client() - search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - search = search.where(Asset.GUID.eq(guid)) + results = ( + FluentSearch() + .select() + .where(asset_type.GUID.eq(guid)) + .execute(client=client) + ) elif qualified_name: - search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + results = ( + FluentSearch() + .select() + .where(asset_type.QUALIFIED_NAME.eq(qualified_name)) + .execute(client=client) + ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] if not isinstance(first_result, asset_type): @@ -1481,17 +1497,25 @@ def remove_terms( from pyatlan.model.fluent_search import FluentSearch client = AtlanClient.get_default_client() - search = FluentSearch().select() if guid: if qualified_name: raise ErrorCode.QN_OR_GUID_NOT_BOTH.exception_with_parameters() - search = search.where(Asset.GUID.eq(guid)) + results = ( + FluentSearch() + .select() + .where(asset_type.GUID.eq(guid)) + .execute(client=client) + ) elif qualified_name: - search = search.where(Asset.QUALIFIED_NAME.eq(qualified_name)) + results = ( + FluentSearch() + .select() + .where(asset_type.QUALIFIED_NAME.eq(qualified_name)) + .execute(client=client) + ) else: raise ErrorCode.QN_OR_GUID.exception_with_parameters() - results = search.execute(client=client) if results and results.current_page(): first_result = results.current_page()[0] if not isinstance(first_result, asset_type): From 808c4a1df51f89212e2dd0f80ca5f9611845579f Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Sun, 5 Jan 2025 20:26:24 +0530 Subject: [PATCH 58/66] Corrected the Unit tests --- tests/unit/test_client.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 19c9fa61..40d32277 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -278,8 +278,8 @@ def test_append_terms_invalid_parameters_raises_error( Table, [AtlasGlossaryTerm()], [], - "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist. " - "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist." + " Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", NotFoundError, ), ( @@ -299,7 +299,7 @@ def test_append_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." - "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + " Suggestion: Verify the requested asset type and name exist in your Atlan environment.", NotFoundError, ), ( @@ -309,7 +309,7 @@ def test_append_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." - "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + " Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", NotFoundError, ), ], @@ -380,7 +380,7 @@ def test_replace_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], [], "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist." - "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + " Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", NotFoundError, ), ( @@ -390,7 +390,7 @@ def test_replace_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], [], "ATLAN-PYTHON-404-001 Asset with GUID nonexistent_guid does not exist." - "Suggestion: Verify the GUID of the asset you are trying to retrieve.", + " Suggestion: Verify the GUID of the asset you are trying to retrieve.", NotFoundError, ), ( @@ -400,7 +400,7 @@ def test_replace_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." - "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + " Suggestion: Verify the requested asset type and name exist in your Atlan environment.", NotFoundError, ), ( @@ -410,7 +410,7 @@ def test_replace_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." - "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + " Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", NotFoundError, ), ], @@ -481,7 +481,7 @@ def test_remove_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], [], "ATLAN-PYTHON-404-003 Asset with qualifiedName nonexistent_qualified_name of type Table does not exist." - "Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", + " Suggestion: Verify the qualifiedName and expected type of the asset you are trying to retrieve.", NotFoundError, ), ( @@ -491,7 +491,7 @@ def test_remove_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], [], "ATLAN-PYTHON-404-001 Asset with GUID nonexistent_guid does not exist." - "Suggestion: Verify the GUID of the asset you are trying to retrieve.", + " Suggestion: Verify the GUID of the asset you are trying to retrieve.", NotFoundError, ), ( @@ -501,7 +501,7 @@ def test_remove_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-014 The Table asset could not be found by name: default/abc." - "Suggestion: Verify the requested asset type and name exist in your Atlan environment.", + " Suggestion: Verify the requested asset type and name exist in your Atlan environment.", NotFoundError, ), ( @@ -511,7 +511,7 @@ def test_remove_terms_invalid_parameters_raises_error( [AtlasGlossaryTerm()], ["DifferentTypeAsset"], "ATLAN-PYTHON-404-002 Asset with GUID 123 is not of the type requested: Table." - "Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", + " Suggestion: Verify the GUID and expected type of the asset you are trying to retrieve.", NotFoundError, ), ], From 0bf2ba902802be24a035faa7c1d6a5f8148b9ceb Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Sun, 5 Jan 2025 22:13:49 +0530 Subject: [PATCH 59/66] Corrected the validate_arguments --- pyatlan/client/asset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 0cfd5750..9951867e 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -352,7 +352,7 @@ def find_purposes_by_name( allow_multiple=True, ) - @validate_arguments + @validate_arguments(config=dict(arbitrary_types_allowed=True)) def get_by_qualified_name( self, qualified_name: str, @@ -425,7 +425,7 @@ def get_by_qualified_name( ) return asset - @validate_arguments + @validate_arguments(config=dict(arbitrary_types_allowed=True)) def get_by_guid( self, guid: str, From 7dea89ab9e7fcb17bc5d85ea0e250210c0d77bf9 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Sun, 5 Jan 2025 22:18:46 +0530 Subject: [PATCH 60/66] Corrected the validate_arguments --- pyatlan/client/asset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 75e4d004..3798e97f 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -351,7 +351,7 @@ def find_purposes_by_name( allow_multiple=True, ) - @validate_arguments + @validate_arguments(config=dict(arbitrary_types_allowed=True)) def get_by_qualified_name( self, qualified_name: str, @@ -424,7 +424,7 @@ def get_by_qualified_name( ) return asset - @validate_arguments + @validate_arguments(config=dict(arbitrary_types_allowed=True)) def get_by_guid( self, guid: str, From ac5fef6750736d2dff371dd67f8ca582fdf6656b Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Sun, 5 Jan 2025 22:28:39 +0530 Subject: [PATCH 61/66] Testing: To fix the integration test --- tests/integration/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index 85feac6e..7a285765 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -95,7 +95,7 @@ def announcement(): ) -@pytest.fixture() +@pytest.fixture(scope="module") def database( client: AtlanClient, connection: Connection ) -> Generator[Database, None, None]: From 5dd573b5781585acd7362a6b55df167693d19423 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Sun, 5 Jan 2025 22:46:29 +0530 Subject: [PATCH 62/66] Resolving None-Type Error in attributes or relationships_attributes --- pyatlan/client/asset.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 3798e97f..5c071a5d 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -389,11 +389,9 @@ def get_by_qualified_name( search = ( FluentSearch().select().where(Asset.QUALIFIED_NAME.eq(qualified_name)) ) - for attribute in attributes: # type: ignore[union-attr] + for attribute in attributes or []: # type: ignore[union-attr] search = search.include_on_results(attribute) - for ( - relation_attribute - ) in relationships_attributes: # type: ignore[union-attr] + for relation_attribute in relationships_attributes or []: # type: ignore[union-attr] search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): @@ -459,9 +457,9 @@ def get_by_guid( ): client = AtlanClient.get_default_client() search = FluentSearch().select().where(Asset.GUID.eq(guid)) - for attribute in attributes: # type: ignore[union-attr] + for attribute in attributes or []: # type: ignore[union-attr] search = search.include_on_results(attribute) - for relation_attribute in relationships_attributes: # type: ignore[union-attr] + for relation_attribute in relationships_attributes or []: # type: ignore[union-attr] search = search.include_on_relations(relation_attribute) results = search.execute(client=client) if results and results.current_page(): From 147af9efe6a11c892a71e8d6b33585d9f2408095 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Mon, 6 Jan 2025 19:05:59 +0530 Subject: [PATCH 63/66] corrected test_client.py --- tests/integration/test_client.py | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index ad11531f..cc1f5d78 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -129,7 +129,7 @@ def announcement(): ) -@pytest.fixture(scope="module") +@pytest.fixture() def database( client: AtlanClient, connection: Connection ) -> Generator[Database, None, None]: @@ -467,34 +467,6 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not ): client.asset.get_by_guid(guid, Table, ignore_relationships=False) - -<<<<<<< HEAD -def test_get_by_guid_with_attributes(client: AtlanClient, glossary: AtlasGlossary): - attributes = ["name", "qualified_name"] - - result = client.asset.get_by_guid( - guid=glossary.guid, asset_type=AtlasGlossary, attributes=attributes - ) - assert result.guid == glossary.guid - assert hasattr(result, "attributes") - assert result.attributes.qualified_name is not None - assert result.attributes.name is not None - assert result.attributes.admin_groups is None - - -def test_get_by_QN_with_attributes(client: AtlanClient, glossary: AtlasGlossary): - qualified_name = glossary.qualified_name or "" - result = client.asset.get_by_qualified_name( - qualified_name=qualified_name, - asset_type=AtlasGlossary, - attributes=["name", "qualified_name"], - ) - assert result.qualified_name == glossary.qualified_name - assert hasattr(result, "attributes") - assert result.attributes.qualified_name is not None - assert result.attributes.name is not None - assert result.attributes.admin_groups is None -======= def test_get_by_guid_with_fs(client: AtlanClient, term: AtlasGlossaryTerm): # Default - should call `GET_ENTITY_BY_GUID` API result = client.asset.get_by_guid(guid=term.guid, asset_type=AtlasGlossaryTerm) From f8d008784ca8cac571f9e9c9824eefa4126cdfdf Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Mon, 6 Jan 2025 19:08:23 +0530 Subject: [PATCH 64/66] Correcting test_client.py --- tests/integration/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index cc1f5d78..d1d96a09 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -467,6 +467,7 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not ): client.asset.get_by_guid(guid, Table, ignore_relationships=False) + def test_get_by_guid_with_fs(client: AtlanClient, term: AtlasGlossaryTerm): # Default - should call `GET_ENTITY_BY_GUID` API result = client.asset.get_by_guid(guid=term.guid, asset_type=AtlasGlossaryTerm) @@ -608,7 +609,6 @@ def test_get_by_qualified_name_with_fs(client: AtlanClient, term: AtlasGlossaryT assert result.anchor assert result.anchor.description == f"{TEST_SYSTEM_DESCRIPTION}" assert result.anchor.user_description == f"{TEST_USER_DESCRIPTION}" ->>>>>>> main def test_get_asset_by_guid_bad_with_non_existent_guid_raises_not_found_error( From b025708b60ab55b4e439ee54723cd31f1d30fde7 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 6 Jan 2025 22:13:19 +0530 Subject: [PATCH 65/66] [tests] Ensure test objects are indexed before retrieval --- tests/integration/test_client.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index d1d96a09..d9ddba3c 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -264,8 +264,11 @@ def _test_remove_announcement( def test_append_terms_with_guid( - client: AtlanClient, term1: AtlasGlossaryTerm, database: Database + client: AtlanClient, + term1: AtlasGlossaryTerm, + database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( guid=database.guid, asset_type=Database, terms=[term1] @@ -284,6 +287,7 @@ def test_append_terms_with_qualified_name( term1: AtlasGlossaryTerm, database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( qualified_name=database.qualified_name, asset_type=Database, terms=[term1] @@ -302,6 +306,7 @@ def test_append_terms_using_ref_by_guid_for_term( term1: AtlasGlossaryTerm, database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( qualified_name=database.qualified_name, @@ -323,6 +328,7 @@ def test_replace_a_term( term2: AtlasGlossaryTerm, database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( qualified_name=database.qualified_name, @@ -359,6 +365,7 @@ def test_replace_all_term( term1: AtlasGlossaryTerm, database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( qualified_name=database.qualified_name, @@ -391,6 +398,7 @@ def test_remove_term( term2: AtlasGlossaryTerm, database: Database, ): + time.sleep(5) assert ( database := client.asset.append_terms( qualified_name=database.qualified_name, @@ -469,6 +477,7 @@ def test_get_asset_by_guid_when_table_specified_and_glossary_returned_raises_not def test_get_by_guid_with_fs(client: AtlanClient, term: AtlasGlossaryTerm): + time.sleep(5) # Default - should call `GET_ENTITY_BY_GUID` API result = client.asset.get_by_guid(guid=term.guid, asset_type=AtlasGlossaryTerm) assert isinstance(result, AtlasGlossaryTerm) @@ -538,6 +547,7 @@ def test_get_by_guid_with_fs(client: AtlanClient, term: AtlasGlossaryTerm): def test_get_by_qualified_name_with_fs(client: AtlanClient, term: AtlasGlossaryTerm): + time.sleep(5) # Default - should call `GET_ENTITY_BY_GUID` API assert term and term.qualified_name result = client.asset.get_by_qualified_name( From 31195a555d58f7ff75f83ad747fbf9fa2eab4a61 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 6 Jan 2025 22:14:31 +0530 Subject: [PATCH 66/66] [docs] Removed redundant doctrings --- pyatlan/client/asset.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyatlan/client/asset.py b/pyatlan/client/asset.py index 302e93e1..d075922a 100644 --- a/pyatlan/client/asset.py +++ b/pyatlan/client/asset.py @@ -446,8 +446,6 @@ def get_by_guid( :param attributes: a specific list of attributes to retrieve for the asset :param related_attributes: a specific list of relationships attributes to retrieve for the asset :returns: the requested asset - :param attributes: a specific list of attributes to retrieve for the asset - :param relationships_attributes: a specific list of relationships attributes to retrieve for the asset :raises NotFoundError: if the asset does not exist, or is not of the type requested :raises AtlanError: on any API communication issue """