Source code for monday.types.item

# This file is part of monday-client.
#
# Copyright (C) 2024 Leet Cyber Security <https://leetcybersecurity.com/>
#
# monday-client is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# monday-client is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with monday-client. If not, see <https://www.gnu.org/licenses/>.

"""
Monday.com API item type definitions and structures.

This module contains dataclasses that represent Monday.com item objects,
including items, item lists, and their relationships to boards and groups.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Literal

if TYPE_CHECKING:
    from monday.types.asset import Asset
    from monday.types.board import Board
    from monday.types.column import ColumnValue
    from monday.types.group import Group
    from monday.types.subitem import Subitem
    from monday.types.update import Update
    from monday.types.user import User


[docs] @dataclass class ItemList: """ Type definition for a list of items associated with a board. This structure is used by the Boards.get_items() method to return items grouped by their board ID. """ board_id: str """The ID of the board that contains the items""" items: list[Item] """The list of items belonging to the board"""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" return { 'id': self.board_id, 'items': [ item.to_dict() if hasattr(item, 'to_dict') else item for item in self.items ], }
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> ItemList: """Create from dictionary.""" return cls( board_id=str(data.get('id', '')), items=[ Item.from_dict(item) if isinstance(item, dict) else item for item in data.get('items', []) ], )
[docs] @dataclass class Item: """ Represents a Monday.com item (row) with its data and relationships. This dataclass maps to the Monday.com API item object structure, containing fields like name, column values, updates, and associated board/group information. See Also: https://developer.monday.com/api-reference/reference/items#fields """ assets: list[Asset] | None = None """The item's assets/files""" board: Board | None = None """The board that contains the item""" column_values: list[ColumnValue] | None = None """The item's column values""" created_at: str = '' """The item's creation date. Returned as ``YYYY-MM-DDTHH:MM:SS``""" creator: User | None = None """The item's creator""" creator_id: str = '' """The unique identifier of the item's creator. Returns ``None`` if the item was created by default on the board.""" group: Group | None = None """The item's group""" id: str = '' """The item's unique identifier""" name: str = '' """The item's name""" state: str = '' """The item's state""" subitems: list[Subitem] | None = None """The item's subitems""" subscribers: list[User] | None = None """The item's subscribers""" updated_at: str = '' """The date the item was last updated. Returned as ``YYYY-MM-DDTHH:MM:SS``""" updates: list[Update] | None = None """The item's updates""" email: str = '' """The item's email (when available).""" url: str = '' """The item's link URL (when available).""" relative_link: str = '' """The item's relative path (when available).""" linked_items: list['Item'] | None = None """The item's linked items (when available).""" parent_item: 'Item' | None = None """The parent item, when this Item represents a subitem (e.g., parent_item { ... })."""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" def _convert_list(items: list, converter_name: str = 'to_dict') -> list: """Convert list items using their converter method if available.""" return [ getattr(item, converter_name)() if hasattr(item, converter_name) else item for item in items ] data = { 'assets': _convert_list(self.assets) if self.assets else None, 'board': self.board.to_dict() if self.board else None, 'column_values': _convert_list(self.column_values) if self.column_values else None, 'created_at': self.created_at, 'creator': self.creator.to_dict() if self.creator else None, 'creator_id': self.creator_id, 'group': self.group.to_dict() if self.group else None, 'id': self.id, 'name': self.name, 'state': self.state, 'subitems': _convert_list(self.subitems) if self.subitems else None, 'subscribers': _convert_list(self.subscribers) if self.subscribers else None, 'updated_at': self.updated_at, 'updates': _convert_list(self.updates) if self.updates else None, 'email': self.email, 'url': self.url, 'relative_link': self.relative_link, 'linked_items': _convert_list(self.linked_items) if self.linked_items else None, 'parent_item': self.parent_item.to_dict() if self.parent_item else None, } return {k: v for k, v in data.items() if v}
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> Item: """Create from dictionary.""" from monday.types.asset import Asset # noqa: PLC0415 from monday.types.board import Board # noqa: PLC0415 from monday.types.column import ColumnValue # noqa: PLC0415 from monday.types.group import Group # noqa: PLC0415 from monday.types.subitem import Subitem # noqa: PLC0415 from monday.types.update import Update # noqa: PLC0415 from monday.types.user import User # noqa: PLC0415 return cls( assets=[ Asset.from_dict(asset) if hasattr(Asset, 'from_dict') else asset for asset in data.get('assets', []) ] if data.get('assets') else None, board=Board.from_dict(data['board']) if data.get('board') else None, column_values=[ ColumnValue.from_dict(cv) if hasattr(ColumnValue, 'from_dict') else cv for cv in data.get('column_values', []) ] if data.get('column_values') else None, created_at=str(data.get('created_at', '')), creator=User.from_dict(data['creator']) if data.get('creator') else None, creator_id=str(data.get('creator_id', '')), group=Group.from_dict(data['group']) if data.get('group') else None, id=str(data.get('id', '')), name=str(data.get('name', '')), state=str(data.get('state', '')), subitems=[ Subitem.from_dict(subitem) if hasattr(Subitem, 'from_dict') else subitem for subitem in data.get('subitems', []) ] if data.get('subitems') else None, subscribers=[ User.from_dict(subscriber) if hasattr(User, 'from_dict') else subscriber for subscriber in data.get('subscribers', []) ] if data.get('subscribers') else None, updated_at=str(data.get('updated_at', '')), updates=[ Update.from_dict(update) if hasattr(Update, 'from_dict') else update for update in data.get('updates', []) ] if data.get('updates') else None, email=str(data.get('email', '')), url=str(data.get('url', '')), relative_link=str(data.get('relative_link', '')), linked_items=[ Item.from_dict(li) if isinstance(li, dict) else li for li in data.get('linked_items', []) ] if data.get('linked_items') else None, parent_item=Item.from_dict(data['parent_item']) if data.get('parent_item') else None, )
[docs] @dataclass class ItemsPage: """ Represents a paginated page of Monday.com items with cursor for navigation. This dataclass maps to the Monday.com API items page structure, containing a list of items and a cursor for retrieving the next page. See Also: https://developer.monday.com/api-reference/reference/items#fields """ items: list[Any] | None = None """List of items""" cursor: str = '' """cursor for retrieving the next page of items"""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" result = {} if self.items: result['items'] = [ item.to_dict() if hasattr(item, 'to_dict') else item for item in self.items ] if self.cursor: result['cursor'] = self.cursor return result
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> ItemsPage: """Create from dictionary.""" return cls( items=[ Item.from_dict(item) if hasattr(Item, 'from_dict') else item for item in data.get('items', []) ] if data.get('items') else None, cursor=str(data.get('cursor', '')), )
[docs] @dataclass class OrderBy: """Structure for ordering items in queries.""" column_id: str """The ID of the column to order by""" direction: Literal['asc', 'desc'] = 'asc' """The direction to order items. Defaults to 'asc' if not specified"""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" return {'column_id': self.column_id, 'direction': self.direction}
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> OrderBy: """Create from dictionary.""" return cls( column_id=str(data['column_id']), direction=data.get('direction', 'asc') )
[docs] @dataclass class QueryRule: """Structure for defining item query rules.""" column_id: str """The ID of the column to filter on""" compare_value: list[str | int] """List of values to compare against""" operator: Literal[ 'any_of', 'not_any_of', 'is_empty', 'is_not_empty', 'greater_than', 'greater_than_or_equals', 'lower_than', 'lower_than_or_equal', 'between', 'not_contains_text', 'contains_text', 'contains_terms', 'starts_with', 'ends_with', 'within_the_next', 'within_the_last', ] = 'any_of' """The comparison operator to use. Defaults to ``any_of`` if not specified""" compare_attribute: str = '' """The attribute to compare (optional)"""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" result = { 'column_id': self.column_id, 'compare_value': self.compare_value, 'operator': self.operator, } if self.compare_attribute: result['compare_attribute'] = self.compare_attribute return result
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> QueryRule: """Create from dictionary.""" # Handle cases where column_id might not be present but compare_attribute is column_id = data.get('column_id', '') if not column_id and 'compare_attribute' in data: # Use compare_attribute as column_id if column_id is not present column_id = data['compare_attribute'] return cls( column_id=str(column_id), compare_value=data['compare_value'], operator=data.get('operator', 'any_of'), compare_attribute=data.get('compare_attribute', ''), )
[docs] @dataclass class QueryParams: """ Structure for complex item queries. Example: .. code-block:: python query_params = QueryParams( rules=[ QueryRule( column_id='status', compare_value=['Done', 'In Progress'], operator='any_of', ) ], operator='and', order_by=OrderBy(column_id='date', direction='desc'), ) """ rules: list[QueryRule] = field(default_factory=list) """List of query rules to apply""" operator: Literal['and', 'or'] = 'and' """How to combine multiple rules. Defaults to 'and' if not specified""" order_by: OrderBy | None = None """Optional ordering configuration""" ids: list[int] = field(default_factory=list) """The specific item IDs to return. The maximum is 100."""
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for API requests.""" result = { 'rules': [rule.to_dict() for rule in self.rules], 'operator': self.operator, } if self.order_by: result['order_by'] = self.order_by.to_dict() if self.ids: result['ids'] = self.ids return result
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> QueryParams: """Create from dictionary.""" return cls( rules=[QueryRule.from_dict(rule) for rule in data.get('rules', [])], operator=data.get('operator', 'and'), order_by=OrderBy.from_dict(data['order_by']) if data.get('order_by') else None, ids=data.get('ids', []), )