Skip to content

Timeline

sangfroid.value.Timeline() #

How a Value changes over time.

This class can't be created directly; it should only be created by a Value. It holds no state of its own, other than the reference to the Value which created it.

Attributes:

Name Type Description
parent sangfroid.value.value.Value

the Value which created this Timeline

Source code in sangfroid/value/value.py
353
354
355
356
def __init__(self):
    raise NotImplementedError(
            "Don't construct timelines directly."
            )

add(waypoints, overwrite=False) #

Adds a Waypoint, or a set of Waypoints, to this Timeline.

Parameters:

Name Type Description Default
waypoints [sangfroid.value.value.Waypoint]

the Waypoint (or the list of Waypoints) to add.

required
overwrite bool

if True, new Waypoints will replace existing Waypoints with the same times. Otherwise, if new Waypoints clash with existing Waypoints, we raise ValueError.

False

Raises:

Type Description
ValueError

if overwrite is False, but waypoints contains waypoints which clash with waypoints already on our timeline.

TypeError

if waypoints is neither a Waypoint nor a list of Waypoints; or if a listed Waypoint has a tag which isn't a bs4.Tag.

Source code in sangfroid/value/value.py
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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
def add(self,
        waypoints:['Waypoint'],
        overwrite:bool = False,
        ) -> Self:
    """
    Adds a Waypoint, or a set of Waypoints, to this Timeline.

    Args:
        waypoints: the Waypoint (or the list of Waypoints) to add.
        overwrite: if `True`, new Waypoints will replace existing
            Waypoints with the same times. Otherwise, if new Waypoints
            clash with existing Waypoints, we raise `ValueError`.

    Raises:
        ValueError: if `overwrite` is `False`, but `waypoints` contains
            waypoints which clash with waypoints already on our timeline.
        TypeError: if `waypoints` is neither a Waypoint nor a
            list of Waypoints; or if a listed Waypoint has a tag
            which isn't a `bs4.Tag`.
    """

    def raise_argument_error():
        raise TypeError(
                "The argument to add() "
                "must be either a Waypoint or a list of Waypoints.")

    if isinstance(waypoints, Waypoint):
        waypoints = [waypoints]
    elif isinstance(waypoints, list):
        pass
    else:
        raise_argument_error()

    # check they're sensible
    for w in waypoints:
        if not isinstance(w, Waypoint):
            raise_argument_error()
        elif not isinstance(w.tag, bs4.Tag):
            raise TypeError(
                    f'{w} has a tag of type {type(w.tag)}')

    def fix_up_times(wps):
        return dict([
            (T(wp.tag['time'], ref=self.parent.tag).frames, wp)
            for wp in wps])

    existing = fix_up_times(self.parent._waypoints().values())
    newcomers = fix_up_times(waypoints)

    clashes = [
        (oldtime, newtime)
            for oldtime, old in existing.items()
            for newtime, new in newcomers.items()
            if oldtime==newtime
            ]

    if overwrite:
        for old, _ in clashes:
            del existing[old]
    elif clashes:
        raise ValueError("There are already Waypoints with those "
                         "times in this timeline:\n"
                         f"{clashes}")

    self.parent.is_animated = True

    existing |= newcomers

    self.parent.tag.clear()

    for t, w in sorted(existing.items()):
        self.parent.tag.append(copy.copy(w.tag))

    return self