Skip to content

data_models

ActivityData dataclass

Simple dataclass to cache representation data.

Source code in client/ayon_core/ui/data_models.py
221
222
223
224
225
226
227
228
229
230
231
232
233
@dataclass
class ActivityData:
    """Simple dataclass to cache representation data."""

    representation_id: str = ""
    hash: int = field(init=False)
    activity_list: list[
        CommentModel | VersionPublishModel | StatusChangeModel
    ] = field(default_factory=list)

    def __post_init__(self):
        """Compute the hash of the activity list."""
        self.hash = hash(tuple(self.activity_list))

__post_init__()

Compute the hash of the activity list.

Source code in client/ayon_core/ui/data_models.py
231
232
233
def __post_init__(self):
    """Compute the hash of the activity list."""
    self.hash = hash(tuple(self.activity_list))

CommentCategory dataclass

Model for powerpack activity_categories settings

Source code in client/ayon_core/ui/data_models.py
272
273
274
275
276
277
278
@dataclass
class CommentCategory:
    """Model for powerpack `activity_categories` settings"""

    name: str
    color: str
    access: dict[str, Any]

CommentModel dataclass

Source code in client/ayon_core/ui/data_models.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
@dataclass(unsafe_hash=True)
class CommentModel:
    activity_id: str = ""
    user_full_name: str = ""
    user_name: str = ""
    user_src: str = ""
    comment: str = ""  # type: ignore
    category: str = ""
    category_color: str = ""
    comment_date: str = ""
    short_date: str = field(init=False, hash=False)
    type: ActivityCategory = field(
        init=False, default=ActivityCategory.COMMENT, hash=False
    )
    files: list[FileModel] = field(default_factory=list, hash=False)
    annotations: list[AnnotationModel] = field(
        default_factory=list, hash=False
    )
    _comment: str = field(init=False, repr=False)

    def __post_init__(self):
        """Set the date if not set and compute the short date."""
        if not self.comment_date:
            self.comment_date = datetime.now(timezone.utc).isoformat()

        self.short_date = short_date(self.comment_date)

    @property
    def comment(self):  # noqa: F811
        return self._comment

    @comment.setter
    def comment(self, value: str):
        """Check if the comment contains a checklist."""
        if re.search(RE_HAS_CHECKLIST, str(value)):
            self.type = ActivityCategory.COMMENT | ActivityCategory.CHECKLIST
        self._comment = value

__post_init__()

Set the date if not set and compute the short date.

Source code in client/ayon_core/ui/data_models.py
197
198
199
200
201
202
def __post_init__(self):
    """Set the date if not set and compute the short date."""
    if not self.comment_date:
        self.comment_date = datetime.now(timezone.utc).isoformat()

    self.short_date = short_date(self.comment_date)

EntityMention dataclass

Entity (version or task) that can be mentioned in a comment.

A mention is stored in the comment markdown as [label](entity_type:id).

Source code in client/ayon_core/ui/data_models.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
@dataclass
class EntityMention:
    """Entity (version or task) that can be mentioned in a comment.

    A mention is stored in the comment markdown as
    ``[label](entity_type:id)``.
    """

    entity_type: str  # "version" or "task"
    id: str
    label: str
    context: str = ""  # e.g. product name of a version, folder of a task
    # Material symbol and color of the product type or task type
    icon: str = ""
    color: str = ""
    suffix: str = ""  # e.g. how long ago a version was created

FileModel dataclass

Model for activity attached files.

Attachments could be images, there could be also preview available for them.

Source code in client/ayon_core/ui/data_models.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
@dataclass
class FileModel:
    """Model for activity attached files.

    Attachments could be images, there could be also preview available for
    them.
    """

    id: str
    mime: str
    local_path: str = ""
    thumb_local_path: str = ""
    frame: int = 0
    start_frame: int = 0  # for sequences, to compute the actual frame number

ProjectData dataclass

Model to pass project data - anatomy, users, teams

Source code in client/ayon_core/ui/data_models.py
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
@dataclass
class ProjectData:
    """Model to pass project data - anatomy, users, teams"""

    project_name: str
    users: List[User]
    teams: List[Team]
    anatomy: dict[str, Any]
    comment_category: List[CommentCategory]
    current_user: Optional[User]

    @staticmethod
    def not_set():
        ns = "PROJECT NOT SET"
        return ProjectData(
            project_name=ns,
            users=[],
            teams=[],
            anatomy={},
            comment_category=[],
            current_user=None,
        )

User dataclass

Data model for user

Source code in client/ayon_core/ui/data_models.py
236
237
238
239
240
241
242
243
244
245
@dataclass
class User:
    """Data model for user"""

    name: str
    short_name: str
    full_name: str
    email: str
    avatar_url: str = ""
    avatar_local_path: str = ""

VersionData dataclass

Model to pass enhanced version data

Source code in client/ayon_core/ui/data_models.py
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
@dataclass
class VersionData:
    """Model to pass enhanced version data"""

    id: str
    name: str
    author: str
    tags: list[str]
    status: str
    product_name: str
    task_name: str
    priority: str
    folder_path: str
    assignees: list[str]
    attrib: dict[str, str]
    thumbnail_id: str = ""
    thumbnail_local_path: str = ""

    @staticmethod
    def not_set():
        ns = "VERSION NOT SET"
        return VersionData(
            id=ns,
            name=ns,
            author=ns,
            tags=[],
            status=ns,
            product_name=ns,
            task_name=ns,
            priority=ns,
            folder_path=ns,
            assignees=[],
            attrib={},
            thumbnail_id="",
            thumbnail_local_path="",
        )

VersionPublishModel dataclass

Publish of a version.

Attributes:

Name Type Description
status str

Current status of the published version, not the status it had when it was published. Not shown when empty.

thumbnail_key str

Key of the version thumbnail in the :class:~ayon_core.ui.image_cache.ImageCache. The thumbnail is shown if the key is cached, otherwise the widget asks its thumbnail loader for it. Not shown when empty.

Source code in client/ayon_core/ui/data_models.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
@dataclass(unsafe_hash=True)
class VersionPublishModel:
    """Publish of a version.

    Attributes:
        status: Current status of the published version, not the status
            it had when it was published. Not shown when empty.
        thumbnail_key: Key of the version thumbnail in the
            :class:`~ayon_core.ui.image_cache.ImageCache`. The thumbnail
            is shown if the key is cached, otherwise the widget asks its
            thumbnail loader for it. Not shown when empty.
    """

    activity_id: str = ""
    user_full_name: str = ""
    user_name: str = ""
    user_src: str = ""
    version: str = ""
    product: str = ""
    date: str = ""
    status: str = field(default="", hash=False)
    thumbnail_key: str = field(default="", hash=False)
    short_date: str = field(init=False, hash=False)
    type: ActivityCategory = field(
        init=False, default=ActivityCategory.VERSION_PUBLISH, hash=False
    )

    def __post_init__(self):
        self.short_date = short_date(self.date)

relative_date(date_str)

Format a date as the time passed since, e.g. "13 hours".

This is the wording of the activity feed in the web frontend: only the largest unit, also for dates that are months or years old. It is meant for feeds where the exact date is one hover away, see :func:short_date.

It is not a replacement of :func:ayon_core.tools.utils.delegates.pretty_date, which the tools use for table columns: that one is relative only for the last day and shows the full date after it, because there the date itself matters.

Parameters:

Name Type Description Default
date_str str

Date in ISO format.

required

Returns:

Type Description
str

Time passed in its largest unit, "just now" for the last

str

minute and for a date in the future (e.g. when the clock of the

str

server is ahead), or the input if it can not be parsed.

Source code in client/ayon_core/ui/data_models.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def relative_date(date_str: str) -> str:
    """Format a date as the time passed since, e.g. ``"13 hours"``.

    This is the wording of the activity feed in the web frontend: only
    the largest unit, also for dates that are months or years old. It is
    meant for feeds where the exact date is one hover away, see
    :func:`short_date`.

    It is not a replacement of
    :func:`ayon_core.tools.utils.delegates.pretty_date`, which the tools
    use for table columns: that one is relative only for the last day and
    shows the full date after it, because there the date itself matters.

    Args:
        date_str: Date in ISO format.

    Returns:
        Time passed in its largest unit, ``"just now"`` for the last
        minute and for a date in the future (e.g. when the clock of the
        server is ahead), or the input if it can not be parsed.
    """
    try:
        date = datetime.fromisoformat(date_str).astimezone()
    except (TypeError, ValueError):
        return date_str
    seconds = (datetime.now().astimezone() - date).total_seconds()
    if seconds < 60:
        return "just now"
    unit, count = "minute", int(seconds // 60)
    for larger_unit, size in (
        ("year", 365 * 86400),
        ("month", 30 * 86400),
        ("day", 86400),
        ("hour", 3600),
    ):
        if seconds >= size:
            unit, count = larger_unit, int(seconds // size)
            break
    return f"{count} {unit}{'s' if count > 1 else ''}"