diff --git a/ayon_api/_api.py b/ayon_api/_api.py index c23760665..e7af02f25 100644 --- a/ayon_api/_api.py +++ b/ayon_api/_api.py @@ -802,6 +802,7 @@ def get_users( usernames: Iterable[str] | None = None, emails: Iterable[str] | None = None, fields: Iterable[str] | None = None, + own_attributes: bool = False, ) -> Generator[dict[str, Any], None, None]: """Get Users. @@ -814,6 +815,9 @@ def get_users( emails (Iterable[str] | None): Filter by emails. fields (Iterable[str] | None): Fields to be queried for users. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: Generator[dict[str, Any], None, None]: Queried users. @@ -825,6 +829,7 @@ def get_users( usernames=usernames, emails=emails, fields=fields, + own_attributes=own_attributes, ) @@ -832,6 +837,7 @@ def get_user_by_name( username: str, project_name: str | None = None, fields: Iterable[str] | None = None, + own_attributes: bool = False, ) -> dict[str, Any] | None: """Get user by name using GraphQl. @@ -842,6 +848,9 @@ def get_user_by_name( username (str): Username. project_name (str | None): Define scope of project. fields (Iterable[str] | None): Fields to be queried for users. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: dict[str, Any] | None: User info or None if user is not found. @@ -852,11 +861,13 @@ def get_user_by_name( username=username, project_name=project_name, fields=fields, + own_attributes=own_attributes, ) def get_user( username: str | None = None, + own_attributes: bool = False, ) -> dict[str, Any] | None: """Get user info using REST endpoint. @@ -864,6 +875,9 @@ def get_user( Args: username (str | None): Username. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: dict[str, Any] | None: User info or None if user is not @@ -873,6 +887,7 @@ def get_user( con = get_server_api_connection() return con.get_user( username=username, + own_attributes=own_attributes, ) @@ -5173,8 +5188,9 @@ def get_projects( include_skeleton (bool): Include skeleton projects. fields (Optional[Iterable[str]]): fields to be queried for project. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[ProjectDict, None, None]: Queried projects. @@ -5201,8 +5217,9 @@ def get_project( project_name (str): Name of project. fields (Optional[Iterable[str]]): fields to be queried for project. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[ProjectDict]: Project entity data or None @@ -6128,8 +6145,9 @@ def get_folders( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[FolderDict, None, None]: Queried folder entities. @@ -6172,8 +6190,9 @@ def get_folder_by_id( folder_id (str): Folder id. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None @@ -6205,8 +6224,9 @@ def get_folder_by_path( folder_path (str): Folder path. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None @@ -6240,8 +6260,9 @@ def get_folder_by_name( folder_name (str): Folder name. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None @@ -6552,8 +6573,9 @@ def get_tasks( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[TaskDict, None, None]: Queried task entities. @@ -6593,8 +6615,9 @@ def get_task_by_name( task_name (str): Task name fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. @@ -6624,8 +6647,9 @@ def get_task_by_id( task_id (str): Task id. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. @@ -6677,8 +6701,9 @@ def get_tasks_by_folder_paths( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: dict[str, list[TaskDict]]: Task entities by @@ -6737,8 +6762,9 @@ def get_tasks_by_folder_path( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. """ con = get_server_api_connection() @@ -6772,8 +6798,9 @@ def get_task_by_folder_path( task_name (str): Task name. fields (Optional[Iterable[str]]): Task fields that should be returned. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. diff --git a/ayon_api/_api_helpers/base.py b/ayon_api/_api_helpers/base.py index d852a95b4..6110b5e0d 100644 --- a/ayon_api/_api_helpers/base.py +++ b/ayon_api/_api_helpers/base.py @@ -129,7 +129,9 @@ def get_project( raise NotImplementedError() def get_user( - self, username: Optional[str] = None + self, + username: Optional[str] = None, + own_attributes: bool = False, ) -> Optional[dict[str, Any]]: raise NotImplementedError() diff --git a/ayon_api/_api_helpers/folders.py b/ayon_api/_api_helpers/folders.py index c0cb8341e..b045cd6e4 100644 --- a/ayon_api/_api_helpers/folders.py +++ b/ayon_api/_api_helpers/folders.py @@ -263,8 +263,9 @@ def get_folders( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[FolderDict, None, None]: Queried folder entities. @@ -360,8 +361,9 @@ def get_folder_by_id( folder_id (str): Folder id. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None @@ -396,8 +398,9 @@ def get_folder_by_path( folder_path (str): Folder path. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None @@ -434,8 +437,9 @@ def get_folder_by_name( folder_name (str): Folder name. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[FolderDict]: Folder entity data or None diff --git a/ayon_api/_api_helpers/projects.py b/ayon_api/_api_helpers/projects.py index c7c25d5de..5cd34037c 100644 --- a/ayon_api/_api_helpers/projects.py +++ b/ayon_api/_api_helpers/projects.py @@ -369,8 +369,9 @@ def get_projects( include_skeleton (bool): Include skeleton projects. fields (Optional[Iterable[str]]): fields to be queried for project. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[ProjectDict, None, None]: Queried projects. @@ -430,8 +431,9 @@ def get_project( project_name (str): Name of project. fields (Optional[Iterable[str]]): fields to be queried for project. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[ProjectDict]: Project entity data or None diff --git a/ayon_api/_api_helpers/tasks.py b/ayon_api/_api_helpers/tasks.py index 4c6209443..190e43012 100644 --- a/ayon_api/_api_helpers/tasks.py +++ b/ayon_api/_api_helpers/tasks.py @@ -64,8 +64,9 @@ def get_tasks( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Generator[TaskDict, None, None]: Queried task entities. @@ -137,8 +138,9 @@ def get_task_by_name( task_name (str): Task name fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. @@ -170,8 +172,9 @@ def get_task_by_id( task_id (str): Task id. fields (Optional[Iterable[str]]): Fields that should be returned. All fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. @@ -225,8 +228,9 @@ def get_tasks_by_folder_paths( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: dict[str, list[TaskDict]]: Task entities by @@ -312,8 +316,9 @@ def get_tasks_by_folder_path( fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. """ return self.get_tasks_by_folder_paths( @@ -346,8 +351,9 @@ def get_task_by_folder_path( task_name (str): Task name. fields (Optional[Iterable[str]]): Task fields that should be returned. - own_attributes (Optional[bool]): Attribute values that are - not explicitly set on entity will have 'None' value. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on entity, other + attributes have 'None' value. Returns: Optional[TaskDict]: Task entity data or None if was not found. diff --git a/ayon_api/entity_hub.py b/ayon_api/entity_hub.py index 942fa60ea..bb8aebf0d 100644 --- a/ayon_api/entity_hub.py +++ b/ayon_api/entity_hub.py @@ -3151,7 +3151,7 @@ def from_entity_data(cls, project, entity_hub) -> ProjectEntity: folder_types=project["folderTypes"], task_types=project["taskTypes"], statuses=project["statuses"], - attribs=project["ownAttrib"], + attribs=project["own_attributes"], data=project["data"], active=project["active"], entity_hub=entity_hub, @@ -3324,7 +3324,7 @@ def from_entity_data( path=folder["path"], status=folder["status"], tags=folder["tags"], - attribs=folder["ownAttrib"], + attribs=folder["own_attributes"], data=folder.get("data"), thumbnail_id=folder["thumbnailId"], active=folder["active"], @@ -3521,7 +3521,7 @@ def from_entity_data( label=task["label"], status=task["status"], tags=task["tags"], - attribs=task["ownAttrib"], + attribs=task["own_attributes"], data=task.get("data"), assignees=task["assignees"], thumbnail_id=task["thumbnailId"], diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index b9c8c1f70..41ac0eaf9 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1135,6 +1135,7 @@ def get_users( usernames: Iterable[str] | None = None, emails: Iterable[str] | None = None, fields: Iterable[str] | None = None, + own_attributes: bool = False, ) -> Generator[dict[str, Any], None, None]: """Get Users. @@ -1147,6 +1148,9 @@ def get_users( emails (Iterable[str] | None): Filter by emails. fields (Iterable[str] | None): Fields to be queried for users. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: Generator[dict[str, Any], None, None]: Queried users. @@ -1210,6 +1214,8 @@ def get_users( own_attrib.setdefault(name, None) user["attrib"] = attrib + if own_attributes: + user["own_attributes"] = copy.deepcopy(own_attrib) yield user @@ -1218,6 +1224,7 @@ def get_user_by_name( username: str, project_name: str | None = None, fields: Iterable[str] | None = None, + own_attributes: bool = False, ) -> dict[str, Any] | None: """Get user by name using GraphQl. @@ -1228,6 +1235,9 @@ def get_user_by_name( username (str): Username. project_name (str | None): Define scope of project. fields (Iterable[str] | None): Fields to be queried for users. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: dict[str, Any] | None: User info or None if user is not found. @@ -1240,12 +1250,15 @@ def get_user_by_name( project_name=project_name, usernames={username}, fields=fields, + own_attributes=own_attributes, ): return user return None def get_user( - self, username: str | None = None + self, + username: str | None = None, + own_attributes: bool = False, ) -> dict[str, Any] | None: """Get user info using REST endpoint. @@ -1253,6 +1266,9 @@ def get_user( Args: username (str | None): Username. + own_attributes (bool): Fill 'own_attributes' with + attribute values that are explicitly set on user, other + attributes have 'None' value. Returns: dict[str, Any] | None: User info or None if user is not @@ -1272,7 +1288,10 @@ def get_user( for attr_name, attr_data in attributes.items(): user["attrib"].setdefault(attr_name, attr_data["default"]) + # NOTE 'ownAttrib' is always filled for backwards compatibility fill_own_attribs(user) + if not own_attributes: + user.pop("own_attributes", None) return user def get_headers( diff --git a/ayon_api/utils.py b/ayon_api/utils.py index f5769e7d8..3e1057f67 100644 --- a/ayon_api/utils.py +++ b/ayon_api/utils.py @@ -264,9 +264,11 @@ def get(self, key, default=None): def fill_own_attribs(entity: AnyEntityDict) -> None: """Fill own attributes. - Prepare data with own attributes. Prepare data based on a list of - attribute names in 'ownAttrib' and 'attrib'. If is not attribute in - 'ownAttrib' then it's value is set to 'None'. + Prepare data with own attributes to 'own_attributes'. Prepare data based on + a list of attribute names in 'ownAttrib' and 'attrib'. If is not + attribute in 'ownAttrib' then it's value is set to 'None'. + + 'ownAttrib' is replaced with the same data for backwards compatibility. This can be used with a project, folder or task entity. All other entities don't use hierarchical attributes and 'attrib' values are @@ -285,14 +287,17 @@ def fill_own_attribs(entity: AnyEntityDict) -> None: attributes = set(attributes) own_attrib = {} - entity["ownAttrib"] = own_attrib - for key, value in entity["attrib"].items(): if key not in attributes: own_attrib[key] = None else: own_attrib[key] = copy.deepcopy(value) + entity["own_attributes"] = own_attrib + # TODO remove when nothing uses 'ownAttrib' as dictionary, + # it should be list of attribute names as returned from server + entity["ownAttrib"] = copy.deepcopy(own_attrib) + def _convert_filter_value(value: Any) -> list[Any] | None: if value is None: