Skip to content

temporal

Temporal (time related) traits.

FrameRanged dataclass

Bases: TraitBase

Frame ranged trait model.

Model representing a frame-ranged trait.

Sync with OpenAssetIO MediaCreation Traits. For compatibility with OpenAssetIO, we'll need to handle different names of attributes:

* frame_start -> start_frame
* frame_end -> end_frame
...
frames_per_second is a string to allow various precision

formats. FPS is a floating point number, but it can be also represented as a fraction (e.g. "30000/1001") or as a decimal or even as an irrational number. We need to support all these formats. To work with FPS, we'll need some helper function to convert FPS to Decimal from string.

Attributes:

Name Type Description
name str

Trait name.

description str

Trait description.

id str

id should be a namespaced trait name with a version

frame_start int

Frame start.

frame_end int

Frame end.

frame_in int

Frame in.

frame_out int

Frame out.

frames_per_second str

Frames per second.

step int

Step.

Source code in client/ayon_core/pipeline/traits/temporal.py
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
75
76
77
78
79
80
@dataclass
class FrameRanged(TraitBase):
    """Frame ranged trait model.

    Model representing a frame-ranged trait.

    Sync with OpenAssetIO MediaCreation Traits. For compatibility with
    OpenAssetIO, we'll need to handle different names of attributes:

        * frame_start -> start_frame
        * frame_end -> end_frame
        ...

    Note: frames_per_second is a string to allow various precision
        formats. FPS is a floating point number, but it can be also
        represented as a fraction (e.g. "30000/1001") or as a decimal
        or even as an irrational number. We need to support all these
        formats. To work with FPS, we'll need some helper function
        to convert FPS to Decimal from string.

    Attributes:
        name (str): Trait name.
        description (str): Trait description.
        id (str): id should be a namespaced trait name with a version
        frame_start (int): Frame start.
        frame_end (int): Frame end.
        frame_in (int): Frame in.
        frame_out (int): Frame out.
        frames_per_second (str): Frames per second.
        step (int): Step.
    """

    name: ClassVar[str] = "FrameRanged"
    description: ClassVar[str] = "Frame Ranged Trait"
    id: ClassVar[str] = "ayon.time.FrameRanged.v1"
    persistent: ClassVar[bool] = True
    frame_start: int
    frame_end: int
    frame_in: Optional[int] = None
    frame_out: Optional[int] = None
    frames_per_second: str = None
    step: Optional[int] = None

GapPolicy

Bases: Enum

Gap policy enumeration.

This type defines how to handle gaps in a sequence.

Attributes:

Name Type Description
forbidden int

Gaps are forbidden.

missing int

Gaps are interpreted as missing frames.

hold int

Gaps are interpreted as hold frames (last existing frames).

black int

Gaps are interpreted as black frames.

Source code in client/ayon_core/pipeline/traits/temporal.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class GapPolicy(Enum):
    """Gap policy enumeration.

    This type defines how to handle gaps in a sequence.

    Attributes:
        forbidden (int): Gaps are forbidden.
        missing (int): Gaps are interpreted as missing frames.
        hold (int): Gaps are interpreted as hold frames (last existing frames).
        black (int): Gaps are interpreted as black frames.
    """

    forbidden = auto()
    missing = auto()
    hold = auto()
    black = auto()

Handles dataclass

Bases: TraitBase

Handles trait model.

Handles define the range of frames that are included or excluded from the sequence.

Attributes:

Name Type Description
name str

Trait name.

description str

Trait description.

id str

id should be a namespaced trait name with a version

inclusive bool

Handles are inclusive.

frame_start_handle int

Frame start handle.

frame_end_handle int

Frame end handle.

Source code in client/ayon_core/pipeline/traits/temporal.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
@dataclass
class Handles(TraitBase):
    """Handles trait model.

    Handles define the range of frames that are included or excluded
    from the sequence.

    Attributes:
        name (str): Trait name.
        description (str): Trait description.
        id (str): id should be a namespaced trait name with a version
        inclusive (bool): Handles are inclusive.
        frame_start_handle (int): Frame start handle.
        frame_end_handle (int): Frame end handle.
    """

    name: ClassVar[str] = "Handles"
    description: ClassVar[str] = "Handles Trait"
    id: ClassVar[str] = "ayon.time.Handles.v1"
    persistent: ClassVar[bool] = True
    inclusive: Optional[bool] = False
    frame_start_handle: Optional[int] = None
    frame_end_handle: Optional[int] = None

SMPTETimecode dataclass

Bases: TraitBase

SMPTE Timecode trait model.

Attributes:

Name Type Description
timecode str

SMPTE Timecode HH:MM:SS:FF

Source code in client/ayon_core/pipeline/traits/temporal.py
432
433
434
435
436
437
438
439
440
441
442
443
444
@dataclass
class SMPTETimecode(TraitBase):
    """SMPTE Timecode trait model.

    Attributes:
        timecode (str): SMPTE Timecode HH:MM:SS:FF
    """

    name: ClassVar[str] = "Timecode"
    description: ClassVar[str] = "SMPTE Timecode Trait"
    id: ClassVar[str] = "ayon.time.SMPTETimecode.v1"
    persistent: ClassVar[bool] = True
    timecode: str

Sequence dataclass

Bases: TraitBase

Sequence trait model.

This model represents a sequence trait. Based on the FrameRanged trait and Handles, adding support for gaps policy, frame padding and frame list specification. Regex is used to match frame numbers.

Attributes:

Name Type Description
name str

Trait name.

description str

Trait description.

id str

id should be a namespaced trait name with a version

gaps_policy GapPolicy

Gaps policy - how to handle gaps in sequence.

frame_padding int

Frame padding.

frame_regex str

Frame regex - regular expression to match frame numbers. Must include 'index' named group and 'padding' named group.

frame_spec str

Frame list specification of frames. This takes string like "1-10,20-30,40-50" etc.

Source code in client/ayon_core/pipeline/traits/temporal.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
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
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
@dataclass
class Sequence(TraitBase):
    """Sequence trait model.

    This model represents a sequence trait. Based on the FrameRanged trait
    and Handles, adding support for gaps policy, frame padding and frame
    list specification. Regex is used to match frame numbers.

    Attributes:
        name (str): Trait name.
        description (str): Trait description.
        id (str): id should be a namespaced trait name with a version
        gaps_policy (GapPolicy): Gaps policy - how to handle gaps in
            sequence.
        frame_padding (int): Frame padding.
        frame_regex (str): Frame regex - regular expression to match
            frame numbers. Must include 'index' named group and 'padding'
            named group.
        frame_spec (str): Frame list specification of frames. This takes
            string like "1-10,20-30,40-50" etc.
    """

    name: ClassVar[str] = "Sequence"
    description: ClassVar[str] = "Sequence Trait Model"
    id: ClassVar[str] = "ayon.time.Sequence.v1"
    persistent: ClassVar[bool] = True
    frame_padding: int
    gaps_policy: Optional[GapPolicy] = GapPolicy.forbidden
    frame_regex: Optional[Pattern] = None
    frame_spec: Optional[str] = None

    @classmethod
    def validate_frame_regex(
        cls, v: Optional[Pattern]
    ) -> Optional[Pattern]:
        """Validate frame regex.

        Frame regex must have index and padding named groups.

        Returns:
            Optional[Pattern]: Compiled regex pattern.

        Raises:
            ValueError: If frame regex does not include 'index' and 'padding'

        """
        if v is None:
            return v
        if v and any(s not in v.pattern for s in ["?P<index>", "?P<padding>"]):
            msg = "Frame regex must include 'index' and `padding named groups"
            raise ValueError(msg)
        return v

    def validate_trait(self, representation: Representation) -> None:
        """Validate the trait."""
        super().validate_trait(representation)

        # if there is a FileLocations trait, run validation
        # on it as well

        with contextlib.suppress(MissingTraitError):
            self._validate_file_locations(representation)

    def _validate_file_locations(self, representation: Representation) -> None:
        """Validate file locations trait.

        If along with the Sequence trait, there is a FileLocations trait,
        then we need to validate if the file locations match the frame
        list specification.

        Args:
            representation (Representation): Representation instance.

        """
        from .content import FileLocations
        file_locs: FileLocations = representation.get_trait(
            FileLocations)
        # Validate if the file locations on representation
        # match the frame list (if any).
        # We need to extend the expected frames with Handles.
        frame_start = None
        frame_end = None
        handles_frame_start = None
        handles_frame_end = None
        with contextlib.suppress(MissingTraitError):
            handles: Handles = representation.get_trait(Handles)
            # if handles are inclusive, they should be already
            #  accounted for in the FrameRaged frame spec
            if not handles.inclusive:
                handles_frame_start = handles.frame_start_handle
                handles_frame_end = handles.frame_end_handle
        with contextlib.suppress(MissingTraitError):
            frame_ranged: FrameRanged = representation.get_trait(
                FrameRanged)
            frame_start = frame_ranged.frame_start
            frame_end = frame_ranged.frame_end
        if self.frame_spec is not None:
            self.validate_frame_list(
                file_locs,
                frame_start,
                frame_end,
                handles_frame_start,
                handles_frame_end)

        self.validate_frame_padding(file_locs)

    def validate_frame_list(
            self,
            file_locations: FileLocations,
            frame_start: Optional[int] = None,
            frame_end: Optional[int] = None,
            handles_frame_start: Optional[int] = None,
            handles_frame_end: Optional[int] = None) -> None:
        """Validate a frame list.

        This will take FileLocations trait and validate if the
        file locations match the frame list specification.

        For example, if the frame list is "1-10,20-30,40-50", then
        the frame numbers in the file locations should match
        these frames.

        It will skip the validation if the frame list is not provided.

        Args:
            file_locations (FileLocations): File locations trait.
            frame_start (Optional[int]): Frame start.
            frame_end (Optional[int]): Frame end.
            handles_frame_start (Optional[int]): Frame start handle.
            handles_frame_end (Optional[int]): Frame end handle.

        Raises:
            TraitValidationError: If the frame list does not match
                the expected frames.

        """
        if self.frame_spec is None:
            return

        frames: list[int] = []
        if self.frame_regex:
            frames = self.get_frame_list(
                    file_locations, self.frame_regex)
        else:
            frames = self.get_frame_list(
                    file_locations)

        expected_frames = self.list_spec_to_frames(self.frame_spec)
        if frame_start is None or frame_end is None:
            if min(expected_frames) != frame_start:
                msg = (
                    "Frame start does not match the expected frame start. "
                    f"Expected: {frame_start}, Found: {min(expected_frames)}"
                )
                raise TraitValidationError(self.name, msg)

            if max(expected_frames) != frame_end:
                msg = (
                    "Frame end does not match the expected frame end. "
                    f"Expected: {frame_end}, Found: {max(expected_frames)}"
                )
                raise TraitValidationError(self.name, msg)

        # we need to extend the expected frames with Handles
        if handles_frame_start is not None:
            expected_frames.extend(
                range(
                    min(frames) - handles_frame_start, min(frames) + 1))

        if handles_frame_end is not None:
            expected_frames.extend(
                range(
                    max(frames), max(frames) + handles_frame_end + 1))

        if set(frames) != set(expected_frames):
            msg = (
                "Frame list does not match the expected frames. "
                f"Expected: {expected_frames}, Found: {frames}"
            )
            raise TraitValidationError(self.name, msg)

    def validate_frame_padding(
            self, file_locations: FileLocations) -> None:
        """Validate frame padding.

        This will take FileLocations trait and validate if the
        frame padding matches the expected frame padding.

        Args:
            file_locations (FileLocations): File locations trait.

        Raises:
            TraitValidationError: If frame padding does not match
                the expected frame padding.

        """
        expected_padding = self.get_frame_padding(file_locations)
        if self.frame_padding != expected_padding:
            msg = (
                "Frame padding does not match the expected frame padding. "
                f"Expected: {expected_padding}, Found: {self.frame_padding}"
            )
            raise TraitValidationError(self.name, msg)

    @staticmethod
    def list_spec_to_frames(list_spec: str) -> list[int]:
        """Convert list specification to frames.

        Returns:
            list[int]: List of frame numbers.

        Raises:
            ValueError: If invalid frame number in the list.

        """
        frames = []
        segments = list_spec.split(",")
        for segment in segments:
            ranges = segment.split("-")
            if len(ranges) == 1:
                if not ranges[0].isdigit():
                    msg = (
                        "Invalid frame number "
                        f"in the list: {ranges[0]}"
                    )
                    raise ValueError(msg)
                frames.append(int(ranges[0]))
                continue
            start, end = segment.split("-")
            frames.extend(range(int(start), int(end) + 1))
        return frames

    @staticmethod
    def _get_collection(
        file_locations: FileLocations,
        regex: Optional[Pattern] = None) -> clique.Collection:
        r"""Get the collection from file locations.

        Args:
            file_locations (FileLocations): File locations trait.
            regex (Optional[Pattern]): Regular expression to match
                frame numbers. This is passed to ``clique.assemble()``.
                Default clique pattern is::

                    \.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$

        Returns:
            clique.Collection: Collection instance.

        Raises:
            ValueError: If zero or multiple of collections are found.

        """
        patterns = [regex] if regex else None
        files: list[str] = [
            file.file_path.as_posix()
            for file in file_locations.file_paths
        ]
        src_collections, _ = clique.assemble(files, patterns=patterns)
        if len(src_collections) != 1:
            msg = (
                f"Zero or multiple collections found: {len(src_collections)} "
                "expected 1"
            )
            raise ValueError(msg)
        return src_collections[0]

    @staticmethod
    def get_frame_padding(file_locations: FileLocations) -> int:
        """Get frame padding.

        Returns:
            int: Frame padding.

        """
        src_collection = Sequence._get_collection(file_locations)
        padding = src_collection.padding
        # sometimes Clique doesn't get the padding right, so
        # we need to calculate it manually
        if padding == 0:
            padding = len(str(max(src_collection.indexes)))

        return padding

    @staticmethod
    def get_frame_list(
            file_locations: FileLocations,
            regex: Optional[Pattern] = None,
        ) -> list[int]:
        r"""Get the frame list.

        Args:
            file_locations (FileLocations): File locations trait.
            regex (Optional[Pattern]): Regular expression to match
                frame numbers. This is passed to ``clique.assemble()``.
                Default clique pattern is::

                    \.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$

        Returns:
            list[int]: List of frame numbers.

        """
        src_collection = Sequence._get_collection(file_locations, regex)
        return list(src_collection.indexes)

    def get_frame_pattern(self) -> Pattern:
        """Get frame regex as a pattern.

        If the regex is a string, it will compile it to the pattern.

        Returns:
            Pattern: Compiled regex pattern.

        """
        if self.frame_regex:
            if isinstance(self.frame_regex, str):
                return re.compile(self.frame_regex)
            return self.frame_regex
        return re.compile(
            r"\.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$")

get_frame_list(file_locations, regex=None) staticmethod

Get the frame list.

Parameters:

Name Type Description Default
file_locations FileLocations

File locations trait.

required
regex Optional[Pattern]

Regular expression to match frame numbers. This is passed to clique.assemble(). Default clique pattern is::

\.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$
None

Returns:

Type Description
list[int]

list[int]: List of frame numbers.

Source code in client/ayon_core/pipeline/traits/temporal.py
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
@staticmethod
def get_frame_list(
        file_locations: FileLocations,
        regex: Optional[Pattern] = None,
    ) -> list[int]:
    r"""Get the frame list.

    Args:
        file_locations (FileLocations): File locations trait.
        regex (Optional[Pattern]): Regular expression to match
            frame numbers. This is passed to ``clique.assemble()``.
            Default clique pattern is::

                \.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$

    Returns:
        list[int]: List of frame numbers.

    """
    src_collection = Sequence._get_collection(file_locations, regex)
    return list(src_collection.indexes)

get_frame_padding(file_locations) staticmethod

Get frame padding.

Returns:

Name Type Description
int int

Frame padding.

Source code in client/ayon_core/pipeline/traits/temporal.py
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
@staticmethod
def get_frame_padding(file_locations: FileLocations) -> int:
    """Get frame padding.

    Returns:
        int: Frame padding.

    """
    src_collection = Sequence._get_collection(file_locations)
    padding = src_collection.padding
    # sometimes Clique doesn't get the padding right, so
    # we need to calculate it manually
    if padding == 0:
        padding = len(str(max(src_collection.indexes)))

    return padding

get_frame_pattern()

Get frame regex as a pattern.

If the regex is a string, it will compile it to the pattern.

Returns:

Name Type Description
Pattern Pattern

Compiled regex pattern.

Source code in client/ayon_core/pipeline/traits/temporal.py
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
def get_frame_pattern(self) -> Pattern:
    """Get frame regex as a pattern.

    If the regex is a string, it will compile it to the pattern.

    Returns:
        Pattern: Compiled regex pattern.

    """
    if self.frame_regex:
        if isinstance(self.frame_regex, str):
            return re.compile(self.frame_regex)
        return self.frame_regex
    return re.compile(
        r"\.(?P<index>(?P<padding>0*)\d+)\.\D+\d?$")

list_spec_to_frames(list_spec) staticmethod

Convert list specification to frames.

Returns:

Type Description
list[int]

list[int]: List of frame numbers.

Raises:

Type Description
ValueError

If invalid frame number in the list.

Source code in client/ayon_core/pipeline/traits/temporal.py
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
@staticmethod
def list_spec_to_frames(list_spec: str) -> list[int]:
    """Convert list specification to frames.

    Returns:
        list[int]: List of frame numbers.

    Raises:
        ValueError: If invalid frame number in the list.

    """
    frames = []
    segments = list_spec.split(",")
    for segment in segments:
        ranges = segment.split("-")
        if len(ranges) == 1:
            if not ranges[0].isdigit():
                msg = (
                    "Invalid frame number "
                    f"in the list: {ranges[0]}"
                )
                raise ValueError(msg)
            frames.append(int(ranges[0]))
            continue
        start, end = segment.split("-")
        frames.extend(range(int(start), int(end) + 1))
    return frames

validate_frame_list(file_locations, frame_start=None, frame_end=None, handles_frame_start=None, handles_frame_end=None)

Validate a frame list.

This will take FileLocations trait and validate if the file locations match the frame list specification.

For example, if the frame list is "1-10,20-30,40-50", then the frame numbers in the file locations should match these frames.

It will skip the validation if the frame list is not provided.

Parameters:

Name Type Description Default
file_locations FileLocations

File locations trait.

required
frame_start Optional[int]

Frame start.

None
frame_end Optional[int]

Frame end.

None
handles_frame_start Optional[int]

Frame start handle.

None
handles_frame_end Optional[int]

Frame end handle.

None

Raises:

Type Description
TraitValidationError

If the frame list does not match the expected frames.

Source code in client/ayon_core/pipeline/traits/temporal.py
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def validate_frame_list(
        self,
        file_locations: FileLocations,
        frame_start: Optional[int] = None,
        frame_end: Optional[int] = None,
        handles_frame_start: Optional[int] = None,
        handles_frame_end: Optional[int] = None) -> None:
    """Validate a frame list.

    This will take FileLocations trait and validate if the
    file locations match the frame list specification.

    For example, if the frame list is "1-10,20-30,40-50", then
    the frame numbers in the file locations should match
    these frames.

    It will skip the validation if the frame list is not provided.

    Args:
        file_locations (FileLocations): File locations trait.
        frame_start (Optional[int]): Frame start.
        frame_end (Optional[int]): Frame end.
        handles_frame_start (Optional[int]): Frame start handle.
        handles_frame_end (Optional[int]): Frame end handle.

    Raises:
        TraitValidationError: If the frame list does not match
            the expected frames.

    """
    if self.frame_spec is None:
        return

    frames: list[int] = []
    if self.frame_regex:
        frames = self.get_frame_list(
                file_locations, self.frame_regex)
    else:
        frames = self.get_frame_list(
                file_locations)

    expected_frames = self.list_spec_to_frames(self.frame_spec)
    if frame_start is None or frame_end is None:
        if min(expected_frames) != frame_start:
            msg = (
                "Frame start does not match the expected frame start. "
                f"Expected: {frame_start}, Found: {min(expected_frames)}"
            )
            raise TraitValidationError(self.name, msg)

        if max(expected_frames) != frame_end:
            msg = (
                "Frame end does not match the expected frame end. "
                f"Expected: {frame_end}, Found: {max(expected_frames)}"
            )
            raise TraitValidationError(self.name, msg)

    # we need to extend the expected frames with Handles
    if handles_frame_start is not None:
        expected_frames.extend(
            range(
                min(frames) - handles_frame_start, min(frames) + 1))

    if handles_frame_end is not None:
        expected_frames.extend(
            range(
                max(frames), max(frames) + handles_frame_end + 1))

    if set(frames) != set(expected_frames):
        msg = (
            "Frame list does not match the expected frames. "
            f"Expected: {expected_frames}, Found: {frames}"
        )
        raise TraitValidationError(self.name, msg)

validate_frame_padding(file_locations)

Validate frame padding.

This will take FileLocations trait and validate if the frame padding matches the expected frame padding.

Parameters:

Name Type Description Default
file_locations FileLocations

File locations trait.

required

Raises:

Type Description
TraitValidationError

If frame padding does not match the expected frame padding.

Source code in client/ayon_core/pipeline/traits/temporal.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
def validate_frame_padding(
        self, file_locations: FileLocations) -> None:
    """Validate frame padding.

    This will take FileLocations trait and validate if the
    frame padding matches the expected frame padding.

    Args:
        file_locations (FileLocations): File locations trait.

    Raises:
        TraitValidationError: If frame padding does not match
            the expected frame padding.

    """
    expected_padding = self.get_frame_padding(file_locations)
    if self.frame_padding != expected_padding:
        msg = (
            "Frame padding does not match the expected frame padding. "
            f"Expected: {expected_padding}, Found: {self.frame_padding}"
        )
        raise TraitValidationError(self.name, msg)

validate_frame_regex(v) classmethod

Validate frame regex.

Frame regex must have index and padding named groups.

Returns:

Type Description
Optional[Pattern]

Optional[Pattern]: Compiled regex pattern.

Raises:

Type Description
ValueError

If frame regex does not include 'index' and 'padding'

Source code in client/ayon_core/pipeline/traits/temporal.py
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
@classmethod
def validate_frame_regex(
    cls, v: Optional[Pattern]
) -> Optional[Pattern]:
    """Validate frame regex.

    Frame regex must have index and padding named groups.

    Returns:
        Optional[Pattern]: Compiled regex pattern.

    Raises:
        ValueError: If frame regex does not include 'index' and 'padding'

    """
    if v is None:
        return v
    if v and any(s not in v.pattern for s in ["?P<index>", "?P<padding>"]):
        msg = "Frame regex must include 'index' and `padding named groups"
        raise ValueError(msg)
    return v

validate_trait(representation)

Validate the trait.

Source code in client/ayon_core/pipeline/traits/temporal.py
161
162
163
164
165
166
167
168
169
def validate_trait(self, representation: Representation) -> None:
    """Validate the trait."""
    super().validate_trait(representation)

    # if there is a FileLocations trait, run validation
    # on it as well

    with contextlib.suppress(MissingTraitError):
        self._validate_file_locations(representation)

Static dataclass

Bases: TraitBase

Static time trait.

Used to define static time (single frame).

Source code in client/ayon_core/pipeline/traits/temporal.py
447
448
449
450
451
452
453
454
455
456
457
@dataclass
class Static(TraitBase):
    """Static time trait.

    Used to define static time (single frame).
    """

    name: ClassVar[str] = "Static"
    description: ClassVar[str] = "Static Time Trait"
    id: ClassVar[str] = "ayon.time.Static.v1"
    persistent: ClassVar[bool] = True