コード例 #1
0
ファイル: _set.py プロジェクト: tamires-consulting/napari
    def __init__(self, data: Iterable[_T] = ()):

        _events = {'changed': None}
        # For inheritance: If the mro already provides an EmitterGroup, add...
        if hasattr(self, 'events') and isinstance(self.events, EmitterGroup):
            self.events.add(**_events)
        else:
            # otherwise create a new one
            self.events = EmitterGroup(source=self, **_events)

        self._set: set[_T] = set()
        self.update(data)
コード例 #2
0
def test_event_group_depr():
    events = EmitterGroup(b=None, deprecated={"a": "b"})
    with pytest.warns(FutureWarning):
        assert events.b == events.a
    with pytest.raises(AttributeError):
        events.c.connect()
    with pytest.warns(FutureWarning):
        assert events["b"] == events["a"]
    with pytest.raises(KeyError):
        events["c"].connect()
コード例 #3
0
    def __init__(self, key_frames: KeyFrameList) -> None:
        super().__init__()
        self._key_frames = key_frames
        key_frames.events.inserted.connect(self._rebuild_frame_index)
        key_frames.events.removed.connect(self._rebuild_frame_index)
        key_frames.events.changed.connect(self._rebuild_frame_index)
        key_frames.events.reordered.connect(self._rebuild_frame_index)

        self.events = EmitterGroup(source=self, n_frames=None)

        self.state_interpolation_map: InterpolationMap = {
            "camera.angles": Interpolation.SLERP,
            "camera.zoom": Interpolation.LOG,
        }

        # cache of interpolated viewer states
        self._cache: Dict[int, ViewerState] = {}

        # map of frame number -> (kf0, kf1, fraction)
        self._frame_index: Dict[int, Tuple[KeyFrame, KeyFrame, float]] = {}
        self._rebuild_frame_index()
コード例 #4
0
def test_prune_dead_qt(qtbot):
    qtcalls = 0

    class W(QSpinBox):
        def _set(self, event):
            self.setValue(event.value)
            nonlocal qtcalls
            qtcalls += 1

    wdg = W()

    mock = Mock()
    group = EmitterGroup(None, False, boom=None)
    group.boom.connect(mock)
    group.boom.connect(wdg._set)
    assert len(group.boom.callbacks) == 2

    group.boom(value=1)
    assert qtcalls == 1
    mock.assert_called_once()
    mock.reset_mock()

    with qtbot.waitSignal(wdg.destroyed):
        wdg.close()
        wdg.deleteLater()

    group.boom(value=1)
    mock.assert_called_once()
    assert len(group.boom.callbacks) == 1  # we've lost the qt connection
    assert qtcalls == 1  # qwidget didn't get called again
コード例 #5
0
 class A:
     events = EmitterGroup(boom=None)
コード例 #6
0
 class E:
     events = EmitterGroup(test=None)
コード例 #7
0
 def __init__(self):
     self.events = EmitterGroup(test=None)
コード例 #8
0
ファイル: _set.py プロジェクト: tamires-consulting/napari
class EventedSet(MutableSet[_T]):
    """An unordered collection of unique elements.

    Parameters
    ----------
    data : iterable, optional
        Elements to initialize the set with.

    Events
    ------
    changed (added: Set[_T], removed: Set[_T])
        Emitted when the set changes, includes item(s) that have been added
        and/or removed from the set.
    """

    events: EmitterGroup

    def __init__(self, data: Iterable[_T] = ()):

        _events = {'changed': None}
        # For inheritance: If the mro already provides an EmitterGroup, add...
        if hasattr(self, 'events') and isinstance(self.events, EmitterGroup):
            self.events.add(**_events)
        else:
            # otherwise create a new one
            self.events = EmitterGroup(source=self, **_events)

        self._set: set[_T] = set()
        self.update(data)

    # #### START Required Abstract Methods

    def __contains__(self, x: Any) -> bool:
        return x in self._set

    def __iter__(self) -> Iterator[_T]:
        return iter(self._set)

    def __len__(self) -> int:
        return len(self._set)

    def _pre_add_hook(self, value):
        # for subclasses to potentially check value before adding
        return value

    def add(self, value: _T) -> None:
        """Add an element to the set, if not already present."""
        if value not in self:
            value = self._pre_add_hook(value)
            self._set.add(value)
            self.events.changed(added={value}, removed={})

    def discard(self, value: _T) -> None:
        """Remove an element from a set if it is a member.

        If the element is not a member, do nothing.
        """
        if value in self:
            self._set.discard(value)
            self.events.changed(added={}, removed={value})

    # #### END Required Abstract Methods

    # methods inherited from Set:
    # __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__,
    # __sub__, __xor__, and isdisjoint

    # methods inherited from MutableSet:
    # clear, pop, remove, __ior__, __iand__, __ixor__, and __isub__

    # The rest are for parity with builtins.set:

    def clear(self) -> None:
        if self._set:
            values = set(self)
            self._set.clear()
            self.events.changed(added={}, removed=values)

    def __repr__(self) -> str:
        return f"{type(self).__name__}({repr(self._set)})"

    def update(self, others: Iterable[_T] = ()) -> None:
        """Update this set with the union of this set and others"""
        to_add = set(others).difference(self._set)
        if to_add:
            to_add = {self._pre_add_hook(i) for i in to_add}
            self._set.update(to_add)
            self.events.changed(added=set(to_add), removed={})

    def copy(self) -> EventedSet[_T]:
        """Return a shallow copy of this set."""
        return type(self)(self._set)

    def difference(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return set of all elements that are in this set but not other."""
        return type(self)(self._set.difference(others))

    def difference_update(self, others: Iterable[_T] = ()) -> None:
        """Remove all elements of another set from this set."""
        to_remove = self._set.intersection(others)
        if to_remove:
            self._set.difference_update(to_remove)
            self.events.changed(added={}, removed=set(to_remove))

    def intersection(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return all elements that are in both sets as a new set."""
        return type(self)(self._set.intersection(others))

    def intersection_update(self, others: Iterable[_T] = ()) -> None:
        """Remove all elements of in this set that are not present in other."""
        self.difference_update(self._set.symmetric_difference(others))

    def issubset(self, others: Iterable[_T]) -> bool:
        """Returns whether another set contains this set or not"""
        return self._set.issubset(others)

    def issuperset(self, others: Iterable[_T]) -> bool:
        """Returns whether this set contains another set or not"""
        return self._set.issuperset(others)

    def symmetric_difference(self, others: Iterable[_T]) -> EventedSet[_T]:
        """Returns set of elements that are in exactly one of the sets"""
        return type(self)(self._set.symmetric_difference(others))

    def symmetric_difference_update(self, others: Iterable[_T]) -> None:
        """Update set to the symmetric difference of itself and another.

        This will remove any items in this set that are also in `other`, and
        add any items in others that are not present in this set.
        """
        to_add = set(others).difference(self._set)
        to_remove = self._set.intersection(others)
        self._set.difference_update(to_remove)
        self._set.update(to_add)
        self.events.changed(added=to_add, removed=to_remove)

    def union(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return a set containing the union of sets"""
        return type(self)(self._set.union(others))

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v, field: ModelField):
        """Pydantic validator."""
        from pydantic.utils import sequence_like

        if not sequence_like(v):
            raise TypeError(
                trans._(
                    'Value is not a valid sequence: {value}',
                    deferred=True,
                    value=v,
                )
            )
        if not field.sub_fields:
            return cls(v)

        type_field = field.sub_fields[0]
        errors = []
        for i, v_ in enumerate(v):
            _valid_value, error = type_field.validate(v_, {}, loc=f'[{i}]')
            if error:
                errors.append(error)
        if errors:
            from pydantic import ValidationError

            raise ValidationError(errors, cls)  # type: ignore
        return cls(v)

    def _json_encode(self):
        """Return an object that can be used by json.dumps."""
        return list(self)
コード例 #9
0
ファイル: _set.py プロジェクト: ktaletsk/napari
class EventedSet(MutableSet[_T]):
    """An unordered collection of unique elements.

    Parameters
    ----------
    data : iterable, optional
        Elements to initialize the set with.

    Events
    ------
    added (value: Set[_T])
        emitted after an item or items are added to the set.
        Will not be emitted if item was already in the set when added.
    removed (value: Set[_T])
        emitted after an item or items are removed from the set.
        Will not be emitted if the item was not in the set when discarded.
    """

    events: EmitterGroup

    def __init__(self, data: Iterable[_T] = ()):

        _events = {'added': None, 'removed': None}
        # For inheritance: If the mro already provides an EmitterGroup, add...
        if hasattr(self, 'events') and isinstance(self.events, EmitterGroup):
            self.events.add(**_events)
        else:
            # otherwise create a new one
            self.events = EmitterGroup(source=self, **_events)

        self._set: set[_T] = set()
        self.update(data)

    # #### START Required Abstract Methods

    def __contains__(self, x: Any) -> bool:
        return x in self._set

    def __iter__(self) -> Iterator[_T]:
        return iter(self._set)

    def __len__(self) -> int:
        return len(self._set)

    def add(self, value: _T) -> None:
        if value not in self:
            self._set.add(value)
            self.events.added(value={value})

    def discard(self, value: _T) -> None:
        """Remove an element from a set if it is a member.

        If the element is not a member, do nothing.
        """
        if value in self:
            self._set.discard(value)
            self.events.removed(value={value})

    # #### END Required Abstract Methods

    # methods inherited from Set:
    # __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__,
    # __sub__, __xor__, and isdisjoint

    # methods inherited from MutableSet:
    # clear, pop, remove, __ior__, __iand__, __ixor__, and __isub__

    # The rest are for parity with builtins.set:

    def clear(self) -> None:
        if self._set:
            values = set(self._set)
            self._set.clear()
            self.events.removed(value=values)

    def __repr__(self) -> str:
        return f"{type(self).__name__}({repr(self._set)})"

    def update(self, others: Iterable[_T] = ()) -> None:
        """Update this set with the union of this set and others"""
        to_add = set(others).difference(self._set)
        if to_add:
            self._set.update(to_add)
            self.events.added(value=to_add)

    def copy(self) -> EventedSet[_T]:
        """Return a shallow copy of this set."""
        return EventedSet(self._set)

    def difference(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return set of all elements that are in this set but not other."""
        return EventedSet(self._set.difference(others))

    def difference_update(self, others: Iterable[_T] = ()) -> None:
        """Remove all elements of another set from this set."""
        to_remove = self._set.intersection(others)
        if to_remove:
            self._set.difference_update(others)
            self.events.removed(value=to_remove)

    def intersection(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return all elements that are in both sets as a new set."""
        return EventedSet(self._set.intersection(others))

    def intersection_update(self, others: Iterable[_T] = ()) -> None:
        """Remove all elements of in this set that are not present in other."""
        self.difference_update(self._set.symmetric_difference(others))

    def issubset(self, others: Iterable[_T]) -> bool:
        """Returns whether another set contains this set or not"""
        return self._set.issubset(others)

    def issuperset(self, others: Iterable[_T]) -> bool:
        """Returns whether this set contains another set or not"""
        return self._set.issuperset(others)

    def symmetric_difference(self, others: Iterable[_T]) -> EventedSet[_T]:
        """Returns set of elements that are in exactly one of the sets"""
        return EventedSet(self._set.symmetric_difference(others))

    def symmetric_difference_update(self, others: Iterable[_T]) -> None:
        """Update set to the symmetric difference of itself and another.

        This will remove any items in this set that are also in `other`, and
        add any items in others that are not present in this set.
        """
        to_remove = self._set.intersection(others)
        to_add = set(others).difference(self)
        if to_remove:
            self._set.difference_update(others)
            self.events.removed(value=to_remove)
        if to_add:
            self._set.update(to_add)
            self.events.added(value=to_add)

    def union(self, others: Iterable[_T] = ()) -> EventedSet[_T]:
        """Return a set containing the union of sets"""
        return EventedSet(self._set.union(others))
コード例 #10
0
class FrameSequence(Sequence[ViewerState]):
    """Final sequence of of rendered animation frames, based on keyframes.

    This object acts like an immutable sequence of frames, interpolated from
    a sequence of (mutable) KeyFrames.  It can be indexed at any (valid) frame
    in the animation, and will inteprolate (and cache) viewer state on demand.

    If the KeyFrameList changes in any way, the cache is cleared.

    Parameters
    ----------
    key_frames : KeyFrameList
        A KeyFrameList from which to render the final frame sequence.
    """

    def __init__(self, key_frames: KeyFrameList) -> None:
        super().__init__()
        self._key_frames = key_frames
        key_frames.events.inserted.connect(self._rebuild_frame_index)
        key_frames.events.removed.connect(self._rebuild_frame_index)
        key_frames.events.changed.connect(self._rebuild_frame_index)
        key_frames.events.reordered.connect(self._rebuild_frame_index)

        self.events = EmitterGroup(source=self, n_frames=None)

        self.state_interpolation_map: InterpolationMap = {
            "camera.angles": Interpolation.SLERP,
            "camera.zoom": Interpolation.LOG,
        }

        # cache of interpolated viewer states
        self._cache: Dict[int, ViewerState] = {}

        # map of frame number -> (kf0, kf1, fraction)
        self._frame_index: Dict[int, Tuple[KeyFrame, KeyFrame, float]] = {}
        self._rebuild_frame_index()

    def _rebuild_frame_index(self, event=None):
        """Create a map of frame number -> (kf0, kf1, fraction)"""
        self._frame_index.clear()
        self._cache.clear()
        if len(self._key_frames) < 2:
            self.events.n_frames(value=len(self))
            return

        f = 0
        for kf0, kf1 in pairwise(self._key_frames):
            for s in range(kf1.steps):
                fraction = kf1.ease(s / kf1.steps)
                self._frame_index[f] = (kf0, kf1, fraction)
                f += 1
        self._frame_index[f] = (kf1, kf1, 0)
        self.events.n_frames(value=len(self))

    def __len__(self) -> int:
        """The total frame count of the animation"""
        return len(self._frame_index)

    def __getitem__(self, key: int) -> ViewerState:
        """Get the interpolated state at frame `key` in the animation."""
        if key < 0:
            key += len(self)
        if key not in self._cache:
            try:
                kf0, kf1, frac = self._frame_index[key]
            except KeyError:
                raise IndexError(
                    f"Frame index ({key}) out of range ({len(self)} frames)"
                )
            if frac == 0:
                self._cache[key] = kf0.viewer_state
            else:
                self._cache[key] = self._interpolate_state(
                    kf0.viewer_state,
                    kf1.viewer_state,
                    frac,
                    self.state_interpolation_map,
                )

        return self._cache[key]

    def _interpolate_state(
        self,
        from_state: ViewerState,
        to_state: ViewerState,
        fraction: float,
        state_interpolation_map: Optional[InterpolationMap] = None,
    ):
        """Interpolate a state between two states

        Parameters
        ----------
        from_state : ViewerState
            Description of initial viewer state.
        to_state : ViewerState
            Description of final viewer state.
        fraction : float
            Interpolation fraction, must be between `0` and `1`.
            A value of `0` will return the initial state. A
            value of `1` will return the final state.
        state_interpolation_map : dict
            Dictionary relating state attributes to interpolation functions.

        Returns
        -------
        state : dict
            Description of viewer state.
        """
        from .utils import keys_to_list, nested_get, nested_set

        interp_map = state_interpolation_map or self.state_interpolation_map

        state = {}
        sep = "."

        from_state = asdict(from_state)
        to_state = asdict(to_state)

        for keys in keys_to_list(from_state):
            v0 = nested_get(from_state, keys)
            v1 = nested_get(to_state, keys)

            interp_func = interp_map.get(sep.join(keys), Interpolation.DEFAULT)

            nested_set(state, keys, interp_func(v0, v1, fraction))

        return ViewerState(**state)

    def iter_frames(
        self,
        viewer: napari.viewer.Viewer,
        canvas_only: bool = True,
        scale_factor: float = None,
    ) -> Iterator[np.ndarray]:
        """Iterate over interpolated viewer states, and yield rendered frames."""
        for i, state in enumerate(self):
            frame = state.render(viewer, canvas_only=canvas_only)

            if scale_factor is not None:
                from scipy import ndimage as ndi

                frame = ndi.zoom(frame, (scale_factor, scale_factor, 1))
                frame = frame.astype(np.uint8)
            yield frame