|
32 | 32 | GET_ENTITY_BY_UNIQUE_ATTRIBUTE,
|
33 | 33 | GET_LINEAGE,
|
34 | 34 | GET_ROLES,
|
| 35 | + GET_GROUPS, |
35 | 36 | INDEX_SEARCH,
|
36 | 37 | PARTIAL_UPDATE_ENTITY_BY_ATTRIBUTE,
|
37 | 38 | UPDATE_ENTITY_BY_ATTRIBUTE,
|
| 39 | + CREATE_GROUP, |
| 40 | + DELETE_GROUP, |
| 41 | + UPDATE_GROUP, |
38 | 42 | )
|
39 | 43 | from pyatlan.error import AtlanError, NotFoundError
|
40 | 44 | from pyatlan.exceptions import AtlanServiceException, InvalidRequestException
|
|
69 | 73 | AtlanTypeCategory,
|
70 | 74 | CertificateStatus,
|
71 | 75 | )
|
| 76 | +from pyatlan.model.group import ( |
| 77 | + GroupResponse, |
| 78 | + AtlanGroup, |
| 79 | + CreateGroupResponse, |
| 80 | + CreateGroupRequest, |
| 81 | +) |
72 | 82 | from pyatlan.model.lineage import LineageRequest, LineageResponse
|
73 | 83 | from pyatlan.model.response import AssetMutationResponse
|
74 | 84 | from pyatlan.model.role import RoleResponse
|
@@ -123,7 +133,7 @@ def get_session():
|
123 | 133 | return session
|
124 | 134 |
|
125 | 135 |
|
126 |
| -def _build_typdef_request(typedef: TypeDef) -> TypeDefResponse: |
| 136 | +def _build_typedef_request(typedef: TypeDef) -> TypeDefResponse: |
127 | 137 | if isinstance(typedef, ClassificationDef):
|
128 | 138 | # Set up the request payload...
|
129 | 139 | payload = TypeDefResponse(
|
@@ -263,6 +273,8 @@ def _call_api(
|
263 | 273 | try:
|
264 | 274 | if (
|
265 | 275 | response.content is None
|
| 276 | + or response.content == "null" |
| 277 | + or len(response.content) == 0 |
266 | 278 | or response.status_code == HTTPStatus.NO_CONTENT
|
267 | 279 | ):
|
268 | 280 | return None
|
@@ -354,6 +366,88 @@ def get_all_roles(self) -> RoleResponse:
|
354 | 366 | raw_json = self._call_api(GET_ROLES.format_path_with_params())
|
355 | 367 | return RoleResponse(**raw_json)
|
356 | 368 |
|
| 369 | + def create_group( |
| 370 | + self, |
| 371 | + group: AtlanGroup, |
| 372 | + user_ids: Optional[list[str]] = None, |
| 373 | + ) -> CreateGroupResponse: |
| 374 | + payload = CreateGroupRequest(group=group, user_ids=user_ids) |
| 375 | + raw_json = self._call_api(CREATE_GROUP, request_obj=payload, exclude_unset=True) |
| 376 | + return CreateGroupResponse(**raw_json) |
| 377 | + |
| 378 | + def update_group( |
| 379 | + self, |
| 380 | + group: AtlanGroup, |
| 381 | + ) -> None: |
| 382 | + self._call_api( |
| 383 | + UPDATE_GROUP.format_path_with_params(group.id), |
| 384 | + request_obj=group, |
| 385 | + exclude_unset=True, |
| 386 | + ) |
| 387 | + |
| 388 | + def purge_group( |
| 389 | + self, |
| 390 | + guid: str, |
| 391 | + ) -> None: |
| 392 | + self._call_api(DELETE_GROUP.format_path({"group_guid": guid})) |
| 393 | + |
| 394 | + def get_groups( |
| 395 | + self, |
| 396 | + limit: Optional[int] = None, |
| 397 | + post_filter: Optional[str] = None, |
| 398 | + sort: Optional[str] = None, |
| 399 | + count: bool = True, |
| 400 | + offset: int = 0, |
| 401 | + ) -> GroupResponse: |
| 402 | + query_params: dict[str, str] = { |
| 403 | + "count": str(count), |
| 404 | + "offset": str(offset), |
| 405 | + } |
| 406 | + if limit is not None: |
| 407 | + query_params["limit"] = str(limit) |
| 408 | + if post_filter is not None: |
| 409 | + query_params["filter"] = post_filter |
| 410 | + if sort is not None: |
| 411 | + query_params["sort"] = sort |
| 412 | + raw_json = self._call_api(GET_GROUPS.format_path_with_params(), query_params) |
| 413 | + return GroupResponse(**raw_json) |
| 414 | + |
| 415 | + def get_all_groups(self) -> list[AtlanGroup]: |
| 416 | + """ |
| 417 | + Retrieve all groups defined in Atlan. |
| 418 | + """ |
| 419 | + groups: list[AtlanGroup] = [] |
| 420 | + offset = 0 |
| 421 | + limit = 100 |
| 422 | + response: Optional[GroupResponse] = self.get_groups( |
| 423 | + offset=offset, limit=limit, sort="createdAt" |
| 424 | + ) |
| 425 | + while response: |
| 426 | + if page := response.records: |
| 427 | + groups.extend(page) |
| 428 | + offset += limit |
| 429 | + response = self.get_groups(offset=offset, limit=limit, sort="createdAt") |
| 430 | + else: |
| 431 | + response = None |
| 432 | + return groups |
| 433 | + |
| 434 | + def get_group_by_name( |
| 435 | + self, alias: str, limit: int = 100 |
| 436 | + ) -> Optional[list[AtlanGroup]]: |
| 437 | + """ |
| 438 | + Retrieve all groups with a name that contains the provided string. |
| 439 | + (This could include a complete group name, in which case there should be at most |
| 440 | + a single item in the returned list, or could be a partial group name to retrieve |
| 441 | + all groups with that naming convention.) |
| 442 | + """ |
| 443 | + if response := self.get_groups( |
| 444 | + offset=0, |
| 445 | + limit=limit, |
| 446 | + post_filter='{"$and":[{"alias":{"$ilike":"%' + alias + '%"}}]}', |
| 447 | + ): |
| 448 | + return response.records |
| 449 | + return None |
| 450 | + |
357 | 451 | @validate_arguments()
|
358 | 452 | def get_asset_by_qualified_name(
|
359 | 453 | self,
|
@@ -549,32 +643,59 @@ def get_typedefs(self, type_category: AtlanTypeCategory) -> TypeDefResponse:
|
549 | 643 | return TypeDefResponse(**raw_json)
|
550 | 644 |
|
551 | 645 | def create_typedef(self, typedef: TypeDef) -> TypeDefResponse:
|
552 |
| - payload = _build_typdef_request(typedef) |
| 646 | + payload = _build_typedef_request(typedef) |
553 | 647 | raw_json = self._call_api(
|
554 | 648 | CREATE_TYPE_DEFS, request_obj=payload, exclude_unset=True
|
555 | 649 | )
|
556 | 650 | _refresh_caches(typedef)
|
557 | 651 | return TypeDefResponse(**raw_json)
|
558 | 652 |
|
559 | 653 | def update_typedef(self, typedef: TypeDef) -> TypeDefResponse:
|
560 |
| - payload = _build_typdef_request(typedef) |
| 654 | + payload = _build_typedef_request(typedef) |
561 | 655 | raw_json = self._call_api(
|
562 | 656 | UPDATE_TYPE_DEFS, request_obj=payload, exclude_unset=True
|
563 | 657 | )
|
564 | 658 | _refresh_caches(typedef)
|
565 | 659 | return TypeDefResponse(**raw_json)
|
566 | 660 |
|
567 |
| - def purge_typedef(self, internal_name: str) -> None: |
568 |
| - self._call_api(DELETE_TYPE_DEF_BY_NAME.format_path_with_params(internal_name)) |
569 |
| - # TODO: if we know which kind of typedef is being purged, we only need |
570 |
| - # to refresh that particular cache |
571 |
| - from pyatlan.cache.classification_cache import ClassificationCache |
572 |
| - from pyatlan.cache.custom_metadata_cache import CustomMetadataCache |
573 |
| - from pyatlan.cache.enum_cache import EnumCache |
| 661 | + def purge_typedef(self, name: str, typedef_type: type) -> None: |
| 662 | + if typedef_type == CustomMetadataDef: |
| 663 | + from pyatlan.cache.custom_metadata_cache import CustomMetadataCache |
574 | 664 |
|
575 |
| - ClassificationCache.refresh_cache() |
576 |
| - CustomMetadataCache.refresh_cache() |
577 |
| - EnumCache.refresh_cache() |
| 665 | + internal_name = CustomMetadataCache.get_id_for_name(name) |
| 666 | + elif typedef_type == EnumDef: |
| 667 | + internal_name = name |
| 668 | + elif typedef_type == ClassificationDef: |
| 669 | + from pyatlan.cache.classification_cache import ClassificationCache |
| 670 | + |
| 671 | + internal_name = str(ClassificationCache.get_id_for_name(name)) |
| 672 | + else: |
| 673 | + raise InvalidRequestException( |
| 674 | + message=f"Unable to purge type definitions of type: {typedef_type}", |
| 675 | + ) |
| 676 | + # Throw an invalid request exception |
| 677 | + if internal_name: |
| 678 | + self._call_api( |
| 679 | + DELETE_TYPE_DEF_BY_NAME.format_path_with_params(internal_name) |
| 680 | + ) |
| 681 | + else: |
| 682 | + raise NotFoundError( |
| 683 | + message=f"Unable to find {typedef_type} with name: {name}", |
| 684 | + code="ATLAN-PYTHON-404-000", |
| 685 | + ) |
| 686 | + |
| 687 | + if typedef_type == CustomMetadataDef: |
| 688 | + from pyatlan.cache.custom_metadata_cache import CustomMetadataCache |
| 689 | + |
| 690 | + CustomMetadataCache.refresh_cache() |
| 691 | + elif typedef_type == EnumDef: |
| 692 | + from pyatlan.cache.enum_cache import EnumCache |
| 693 | + |
| 694 | + EnumCache.refresh_cache() |
| 695 | + elif typedef_type == ClassificationDef: |
| 696 | + from pyatlan.cache.classification_cache import ClassificationCache |
| 697 | + |
| 698 | + ClassificationCache.refresh_cache() |
578 | 699 |
|
579 | 700 | @validate_arguments()
|
580 | 701 | def add_classifications(
|
|
0 commit comments