Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions pyatlan/generator/templates/methods/asset/data_product.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,28 @@
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
client: Optional[AtlanClient] = None,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct:
# Mirror UI default: when a client is provided and no owners are
# specified, seed owner_users with the calling user.
if client is not None and owner_users is None:
current_username = client.user.get_current().username
if current_username:
owner_users = {current_username}
attributes = DataProduct.Attributes.create(
name=name,
domain_qualified_name=domain_qualified_name,
asset_selection=asset_selection,
daap_visibility=daap_visibility,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)
return cls(attributes=attributes)

Expand All @@ -23,6 +40,12 @@
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
client: Optional[AtlanClient] = None,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct:
warn(
(
Expand All @@ -36,6 +59,12 @@
name=name,
domain_qualified_name=domain_qualified_name,
asset_selection=asset_selection,
client=client,
daap_visibility=daap_visibility,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)

@classmethod
Expand Down
10 changes: 10 additions & 0 deletions pyatlan/generator/templates/methods/attribute/data_product.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct.Attributes:
validate_required_fields(
["name", "domain_qualified_name", "asset_selection"],
Expand All @@ -28,4 +33,9 @@
domain_qualified_name
),
daap_status=DataProductStatus.ACTIVE,
daap_visibility=daap_visibility or DataProductVisibility.PRIVATE,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)
39 changes: 39 additions & 0 deletions pyatlan/model/assets/core/data_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,28 @@ def creator(
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
client: Optional[AtlanClient] = None,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct:
# Mirror UI default: when a client is provided and no owners are
# specified, seed owner_users with the calling user.
if client is not None and owner_users is None:
current_username = client.user.get_current().username
if current_username:
owner_users = {current_username}
attributes = DataProduct.Attributes.create(
name=name,
domain_qualified_name=domain_qualified_name,
asset_selection=asset_selection,
daap_visibility=daap_visibility,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)
return cls(attributes=attributes)

Expand All @@ -64,6 +81,12 @@ def create(
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
client: Optional[AtlanClient] = None,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct:
warn(
(
Expand All @@ -77,6 +100,12 @@ def create(
name=name,
domain_qualified_name=domain_qualified_name,
asset_selection=asset_selection,
client=client,
daap_visibility=daap_visibility,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)

@classmethod
Expand Down Expand Up @@ -633,6 +662,11 @@ def create(
name: StrictStr,
domain_qualified_name: StrictStr,
asset_selection: IndexSearchRequest,
daap_visibility: Optional[DataProductVisibility] = None,
daap_visibility_users: Optional[Set[str]] = None,
daap_visibility_groups: Optional[Set[str]] = None,
owner_users: Optional[Set[str]] = None,
owner_groups: Optional[Set[str]] = None,
) -> DataProduct.Attributes:
validate_required_fields(
["name", "domain_qualified_name", "asset_selection"],
Expand All @@ -654,6 +688,11 @@ def create(
domain_qualified_name
),
daap_status=DataProductStatus.ACTIVE,
daap_visibility=daap_visibility or DataProductVisibility.PRIVATE,
daap_visibility_users=daap_visibility_users,
daap_visibility_groups=daap_visibility_groups,
owner_users=owner_users,
owner_groups=owner_groups,
)

attributes: DataProduct.Attributes = Field(
Expand Down
14 changes: 14 additions & 0 deletions tests/integration/data_mesh_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
CertificateStatus,
DataContractStatus,
DataProductStatus,
DataProductVisibility,
EntityStatus,
)
from pyatlan.model.fluent_search import FluentSearch
Expand Down Expand Up @@ -266,6 +267,7 @@ def product(
name=DATA_PRODUCT_NAME,
asset_selection=assets,
domain_qualified_name=domain.qualified_name,
client=client,
)
product.output_ports = [table]
response = client.asset.save(product)
Expand All @@ -288,6 +290,14 @@ def test_product(client: AtlanClient, product: DataProduct):
assert re.search(DATA_PRODUCT_QN_REGEX, product.qualified_name)
assert re.search(DATA_DOMAIN_QN_REGEX, product.parent_domain_qualified_name)
assert re.search(DATA_DOMAIN_QN_REGEX, product.super_domain_qualified_name)
# BLDX-1252: default-path visibility must be PRIVATE and status ACTIVE so
# the marketplace Overview "Assets" tile renders.
assert product.daap_visibility == DataProductVisibility.PRIVATE
assert product.daap_status == DataProductStatus.ACTIVE
# BLDX-1252: when client is passed, owner_users defaults to the calling user.
current_username = client.user.get_current().username
assert current_username
assert product.owner_users == {current_username}


@pytest.fixture(scope="module")
Expand Down Expand Up @@ -457,6 +467,10 @@ def test_retrieve_product(client: AtlanClient, product: DataProduct):
assert test_product.name == product.name
assert test_product.certificate_status == CERTIFICATE_STATUS
assert test_product.certificate_status_message == CERTIFICATE_MESSAGE
# BLDX-1252: server must persist the default daap_visibility/daap_status.
# test_update_product does not touch either field.
assert test_product.daap_visibility == DataProductVisibility.PRIVATE
assert test_product.daap_status == DataProductStatus.ACTIVE


@pytest.mark.order(after="test_update_contract")
Expand Down
63 changes: 62 additions & 1 deletion tests/unit/model/data_product_test.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from json import dumps, load, loads
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from pyatlan.client.atlan import AtlanClient
from pyatlan.errors import InvalidRequestError
from pyatlan.model.assets import AtlasGlossary, DataProduct
from pyatlan.model.enums import CertificateStatus, DataProductStatus
from pyatlan.model.enums import (
CertificateStatus,
DataProductStatus,
DataProductVisibility,
)
from pyatlan.model.fluent_search import CompoundQuery, FluentSearch
from pyatlan.model.search import IndexSearchRequest
from tests.unit.model.constants import (
Expand Down Expand Up @@ -121,9 +126,64 @@ def test_create(
expected_asset_dsl = dumps(data_product_assets_dsl_json, sort_keys=True)
assert test_asset_dsl == expected_asset_dsl
assert test_product.data_product_assets_playbook_filter == ASSETS_PLAYBOOK_FILTER
assert test_product.daap_status == DataProductStatus.ACTIVE
assert test_product.daap_visibility == DataProductVisibility.PRIVATE
_assert_product(test_product)


def test_create_defaults_owner_users_to_current_user_when_client_provided(
data_product_asset_selection: IndexSearchRequest,
):
mock_client = MagicMock(spec=AtlanClient)
mock_client.user.get_current.return_value = MagicMock(username="calling-user")

test_product = DataProduct.creator(
name=DATA_PRODUCT_NAME,
asset_selection=data_product_asset_selection,
domain_qualified_name=DATA_DOMAIN_QUALIFIED_NAME,
client=mock_client,
)
assert test_product.owner_users == {"calling-user"}
assert test_product.daap_visibility == DataProductVisibility.PRIVATE


def test_create_explicit_owner_users_takes_precedence_over_client(
data_product_asset_selection: IndexSearchRequest,
):
mock_client = MagicMock(spec=AtlanClient)
mock_client.user.get_current.return_value = MagicMock(username="calling-user")

test_product = DataProduct.creator(
name=DATA_PRODUCT_NAME,
asset_selection=data_product_asset_selection,
domain_qualified_name=DATA_DOMAIN_QUALIFIED_NAME,
client=mock_client,
owner_users={"explicit-owner"},
)
assert test_product.owner_users == {"explicit-owner"}
mock_client.user.get_current.assert_not_called()


def test_create_with_overrides(
data_product_asset_selection: IndexSearchRequest,
):
test_product = DataProduct.create(
name=DATA_PRODUCT_NAME,
asset_selection=data_product_asset_selection,
domain_qualified_name=DATA_DOMAIN_QUALIFIED_NAME,
daap_visibility=DataProductVisibility.PUBLIC,
daap_visibility_users={"user1"},
daap_visibility_groups={"group1"},
owner_users={"owner1"},
owner_groups={"owner_group1"},
)
assert test_product.daap_visibility == DataProductVisibility.PUBLIC
assert test_product.daap_visibility_users == {"user1"}
assert test_product.daap_visibility_groups == {"group1"}
assert test_product.owner_users == {"owner1"}
assert test_product.owner_groups == {"owner_group1"}


def test_create_under_sub_domain(
data_product_asset_selection: IndexSearchRequest, data_product_assets_dsl_json
):
Expand All @@ -147,6 +207,7 @@ def test_create_under_sub_domain(
test_product, qualified_name=DATA_PRODUCT_UNDER_SUB_DOMAIN_QUALIFIED_NAME
)
assert test_product.daap_status == DataProductStatus.ACTIVE
assert test_product.daap_visibility == DataProductVisibility.PRIVATE


def test_create_for_modification():
Expand Down
Loading